TFTP实现 / TFTP Implement


目录

  1. TFTP 的服务器建立过程
  2. TFTP 的客户端建立过程

1 TFTP 的服务器建立过程

服务器建立步骤主要有:

(1)      设定服务器IP和端口号(常用69),建立socket并bind地址;

(2)      设定服务器工作目录;

(3)      建立主循环进行监听,根据收到的信息选择读/写模式;

(4)      (建立新的线程及socket)执行上传下载操作;

(5)      下载操作: block number设置为1—打开需要下载的文件—进入循环—读取512byte数据—发送读取的数据—等待ACK报文(超时重发)—确认opcode—确认数据长度是否结束(结束则进行结束处理,并关闭文件)11—block number +1;

(6)      上传操作: block number 设置为0—发送ACK报文—block number +1—打开新的文件存储上传数据—进入循环—等待接收DATA报文—确认opcode—写入数据—发送ACK报文—确认数据长度是否结束(结束则进行结束处理,并关闭文件)—block number +1。

Note: 关于THTP_Helper 的 TFTP 的加解码过程请参考 TFTP 加解码部分

 import importlib
from TFTP_Helper import *
import socket
from threading import Thread class TFTPServer():
def __init__(self):
ip = '127.0.0.1'
port = 69
address = (ip, port)
self.home_path = 'TFTPServerFile'
self.server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.server.bind(address) def readRequest(self, file_name, addr):
print('<<< RRQ', '\n=== Read request, starting file %s downing to client' % file_name, end='')
sock_down = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
block_num = 1
try:
f = open(self.home_path + '\\' + file_name, 'rb')
except:
# file no found, exit thread
print('=== File %s no found' % file_name)
exit()
while True:
down_data = f.read(512) # data is byte format
sock_down.sendto(TFTPData.encode(block_num, down_data), addr)
print('>>> DATA', block_num)
ack_msg, ack_addr = sock_down.recvfrom(1024)
print('<<< ACK ', block_num)
opcode, ack_block_num = TFTPAck.decode(ack_msg)
assert opcode == 4 and ack_block_num == block_num, 'Invalid ack message.'
if len(down_data) < 512:
block_num = 1
print('=== Transmission of %s completed' % file_name)
f.close()
exit()
block_num += 1
print('=== Close file')
f.close() def writeRequest(self, file_name, addr):
print('<<< WRQ', '\n=== Write request, starting file %s uploading to server' % file_name)
sock_upload = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
block_num = 0
sock_upload.sendto(TFTPAck.encode(block_num), addr)
print('>>> ACK')
try:
f = open('TFTPServerFIle\\Copy-'+file_name, 'wb')
except:
print('=== File "%s" no found' % file_name)
exit()
block_num += 1
while True:
recv_data, addr = sock_upload.recvfrom(1024)
opcode, block_num_recv, data = TFTPData.decode(recv_data)
print('<<< DATA')
if opcode != 3 or block_num != block_num_recv:
print('=== Error Opcode or Block Number')
# TODO: add error msg send and handle here
exit()
f.write(data)
sock_upload.sendto(TFTPAck.encode(block_num), addr)
print('>>> ACK')
if len(data) < 512:
# TODO: add transmission completed handle here
block_num = 1
print('=== File "%s" transmission completed' % file_name)
f.close()
exit()
block_num += 1 def server_run(self):
while True:
print('=== Waiting client')
msg, addr = self.server.recvfrom(1024)
print('<<< Receive a connection from client %s, msg is %s' % (addr, msg))
opcode, file_name = TFTPReadWriteRequest.decode(msg)
cmdSelect = {1: Thread(target=self.readRequest, args=(file_name, addr)),
2: Thread(target=self.writeRequest, args=(file_name, addr))}
try:
cmdSelect[opcode].start()
except:
print('<<< Receive error opcode%s' % opcode)
raise ErrorOpcode server = TFTPServer()
server.server_run()

2 TFTP 的客户端建立过程

客户端建立步骤主要有:

(1)      获取服务器ip和端口;

(2)      下载操作: 建立下载socket—发送RRQ下载请求—设置block number为1—新建文件存储下载数据—进入循环—等待接收DATA报文—确认opcode—写入数据—发送ACK报文—确认数据长度是否结束(结束则进行结束处理,并关闭文件)—block number +1;

(3)      上传操作: 建立上传socket—发送WRQ上传请求—等待ACK报文—设置block number为0—确认opcode—打开需要上传的文件—进入循环—读取数据—发送DATA报文—接收ACK报文—确认opcode—确认数据长度是否结束(结束则进行结束处理,并关闭文件)—block number +1;

 from TFTP_Helper import *
import socket class TFTPClient():
def __init__(self):
server_ip = '127.0.0.1'
port = 69
self.address = (server_ip, port) def readRequest(self, file_name):
sock_down = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
send_data = TFTPReadWriteRequest.encode('r', file_name)
sock_down.sendto(send_data, self.address)
block_num = 1
try:
f = open('TFTPClientFIle\copy-'+file_name, 'wb')
except:
print('--- File "%s" no found' % file_name)
exit()
while True:
recv_data, recv_addr = sock_down.recvfrom(1024)
print('<<< DATA', block_num)
opcode, block_num_recv, data = TFTPData.decode(recv_data)
if opcode != 3 or block_num != block_num_recv:
print('--- Opcode or Block Number Error')
# TODO: add error msg send and handle here
break
f.write(data)
sock_down.sendto(TFTPAck.encode(block_num), recv_addr)
print('>>> ACK ', block_num)
if len(data) < 512:
# TODO: add transmission completed handle here
block_num = 1
print('--- File "%s" transmission completed' % file_name)
f.close()
break
block_num += 1 def writeRequest(self, file_name):
sock_upload = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
send_data = TFTPReadWriteRequest.encode('w', file_name)
sock_upload.sendto(send_data, self.address)
print('>>> WRQ')
recv_data, addr = sock_upload.recvfrom(1024)
print('<<< ACK')
opcode, ack_block = TFTPAck.decode(recv_data)
block_num = 0
if opcode != 4 or ack_block != block_num:
print('--- Error Opcode or Block Number')
# TODO: add error msg send and handle here
exit()
try:
f = open('TFTPClientFIle\\'+file_name, 'rb')
except:
print('--- File "%s" no found' % file_name)
exit()
block_num += 1
while True:
upload_data = f.read(512)
sock_upload.sendto(TFTPData.encode(block_num, upload_data), addr)
print('>>> DATA')
ack_msg, addr = sock_upload.recvfrom(1024)
print('<<< ACK')
opcode, ack_block_num = TFTPAck.decode(ack_msg)
assert opcode == 4 and ack_block_num == block_num, 'Invalid ack message.'
if len(upload_data) < 512:
# TODO: add transmission completed handle here
block_num = 1
print('--- File "%s" transmission completed' % file_name)
f.close()
break
block_num += 1 tftp = TFTPClient()
for file in ['downFile.py', 'downFile.docx', 'downFile.txt', 'downFile.zip']:
tftp.readRequest(file)
for file in ['uploadFile.py', 'uploadFile.docx', 'uploadFile.txt', 'uploadFile.zip']:
tftp.writeRequest(file)

相关阅读


1. TFTP 的基本理论

2. struct 模块

Python的网络编程[2] -> TFTP 协议[1] -> TFTP 的 Python 实现的更多相关文章

  1. Python的网络编程[3] -> BOOTP 协议[1] -> BOOTP 的 Python 实现

    BOOTP实现 / BOOTP Implement 目录 BOOTP 的服务器建立过程 BOOTP 的客户端建立过程 Note: 理论部分请参考文末相关阅读链接 1 BOOTP 的服务器建立过程 服务 ...

  2. Python的网络编程[4] -> DHCP 协议[1] -> DHCP 的 Python 实现

    DHCP实现 / DHCP Implement 目录 DHCP 服务器建立过程 DHCP 报文加码实现过程 下面介绍建立一个简单的DHCP服务器,主要用于对基本的DHCP请求进行响应,目前只提供一个I ...

  3. Python的网络编程[4] -> DHCP 协议[0] -> DHCP 的基本理论

    DHCP协议 / DHCP Protocol 目录 DHCP 基本理论 DHCP 通信流程 DHCP 完整报文 DHCP 的 Optional 字段 DHCP 的报文类型 1 DHCP 基本理论 DH ...

  4. Python的网络编程[3] -> BOOTP 协议[0] -> BOOTP 的基本理论

    BOOTP协议 / BOOTP Protocol 目录 基本理论 BOOTP 与 DHCP 通信流程 数据报文格式 报文加解码实现 1. 基本理论 / Basic Theory BOOTP(Boots ...

  5. Python的网络编程[6] -> Modbus 协议 -> Modbus 的基本理论与 Python 实现

    Modbus协议 / Modbus Protocol 目录 Modbus 协议简介 Modbus RTU协议 Modbus TCP协议与 Python 实现 Modbus 功能码 Modbus TCP ...

  6. Python的网络编程[1] -> FTP 协议[0] -> FTP 的基本理论

    FTP协议 / FTP Protocol FTP全称为File Transfer Protocol(文件传输协议),常用于Internet上控制文件的双向传输,常用的操作有上传和下载.基于TCP/IP ...

  7. Python的网络编程[1] -> FTP 协议[2] -> 使用 ftplib 建立 FTP 客户端

    使用 ftplib 建立 FTP 客户端 用于建立FTP Client,与 pyftplib 建立的 Server 进行通信. 快速导航 1. 模块信息 2. 建立 FTP 客户端 1. 模块信息 1 ...

  8. Python的网络编程[1] -> FTP 协议[1] -> 使用 pyftplib 建立 FTP 服务器

    使用 pyftplib 建立 FTP 服务器 pyftplib 主要用于建立 FTP Server,与 ftplib 建立的 Client 进行通信. 快速导航 1. 模块信息 2. 建立 FTP 服 ...

  9. python之网络编程

    本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道.FIFO.消息队列) 同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 共享内存(匿名的和具名的) 远程过程调用 ...

  10. Python高级网络编程系列之第一篇

    在上一篇中我们简单的说了一下Python中网络编程的基础知识(相关API就不解释了),其中还有什么细节的知识点没有进行说明,如什么是TCP/IP协议有几种状态,什么是TCP三次握手,什么是TCP四次握 ...

随机推荐

  1. php导出数据为CSV文件DEMO

    代码示例: private function _download_send_headers($filename) { // disable caching $now = gmdate("D, ...

  2. 【Soft-Margin Support Vector Machine】林轩田机器学习技术

    Hard-Margin的约束太强了:要求必须把所有点都分开.这样就可能带来overfiiting,把noise也当成正确的样本点了. Hard-Margin有些“学习洁癖”,如何克服这种学习洁癖呢? ...

  3. 程序员必需知道的Windows Shell命令

    Windows系统本来就很人性化的操作系统,操作很方便,但是对于开发人员来说,有些时候改变一些电脑配置或者执行某些任务来说,使用GUI操作反而事倍功半,因此建议使用Shell命令来提高一下工作效率. ...

  4. mysql之select查询:练习

    单表查询: 数据查询命令:select 识别要查询的列 from识别要查询的表 select 运算符: + .-.*./. 加减乘除 等于= 不等于!= 或 <> 大于等于>= 小于 ...

  5. appium-手势密码实现-automationName 是automator2

    上一篇博客已经说了 appium-手势密码实现-automationName 是Appium的情况 下面就说一下automator2的情况: 手势密码的moveTo方法的参数进行了改变. 参数是相对于 ...

  6. uiautomator+cucumber实现移动app自动化测试

    前提 由于公司业务要求,所以自动化测试要达到以下几点: 跨应用的测试 测试用例可读性强 测试报告可读性强 对失败的用例有截图保存并在报告中体现 基于以上几点,在对自动化测试框架选型的时候就选择了uia ...

  7. parameter localparam define的区别

    `define 语法格式 `define A 12 //注意不加:不能忘记" ` " 作用区域 在整个工程中均有效,因为它是可以跨模块的定义 parameter 和 localpa ...

  8. LeetCode-N皇后

                                          LeetCode-N皇后 n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击. ...

  9. Android记事本11

    昨天: Activity的启动模式. 今天: 分析了一些网上的例子的源码. 遇到问题: 无.

  10. java 中基本类型与字符串之间的互相转换

    1. 由 基本数据型态转换成 String String 类别中已经提供了将基本数据型态转换成 String 的 static 方法 也就是 String.valueOf() 这个参数多载的方法 有下 ...