TFTP的工作原理:(原理摘至:点击打开链接)
1、建立一个UDP使他在69端口监听。(我一度认为TFTP就是在69上传输的,其实并不是)
2、建立一个对69端口数据的解析函数。process_tftp_request
3、解析69端口的数据,取出文件名和是什么请求(读/写文件)
4、建立一个用于传输文件的UDP端口(测试时最好绑定到指定端口,以观察控制块的状态)
5、分别处理读文件和写文件。(以读文件为例子)
6、利用文件系统打开总目录。然后搜索这个文件,文件有则打开。
7、建立一个TFTP控制块,主要控制文件块的大小。并从文件中读取512字节,发送第一块512字节的数据到客户端。
8、等待客户端的ACK确认和序号匹配。然则继续发送下一块512字节的数据。
9、重复8,直到读出的块的大小小于512字节,此时文件已经读取完毕了,因为小于512字节了/发送出去LAST
10、等待LAST的ACK之后确认LAST就好。
11、杀掉文件传输控制块,释放TFTP控制块。
1、建立一个UDP使他在69端口监听。(我一度认为TFTP就是在69上传输的,其实并不是)
2、建立一个对69端口数据的解析函数。process_tftp_request
3、解析69端口的数据,取出文件名和是什么请求(读/写文件)
4、建立一个用于传输文件的UDP端口(测试时最好绑定到指定端口,以观察控制块的状态)
5、分别处理读文件和写文件。(以读文件为例子)
6、利用文件系统打开总目录。然后搜索这个文件,文件有则打开。
7、建立一个TFTP控制块,主要控制文件块的大小。并从文件中读取512字节,发送第一块512字节的数据到客户端。
8、等待客户端的ACK确认和序号匹配。然则继续发送下一块512字节的数据。
9、重复8,直到读出的块的大小小于512字节,此时文件已经读取完毕了,因为小于512字节了/发送出去LAST
10、等待LAST的ACK之后确认LAST就好。
11、杀掉文件传输控制块,释放TFTP控制块。
12、结束
首先在win10上安装tftpd32,当作服务器端,虚拟机ubuntu上创建代码作客户端,代码如下,希望多年后还能够看得懂
# -*- coding:utf-8 -*-
import struct,os
from socket import *
def main():
#发送下载请求测试
serverIp = raw_input("请输入目的ip:")
downloadFileName = raw_input("请输入要下载的文件名:")
sendData = struct.pack("!H%dsb5sb"%len(downloadFileName),1,downloadFileName,0,"octet",0)
udpSocket = socket(AF_INET,SOCK_DGRAM)
udpSocket.sendto(sendData,(serverIp,69))
f = open(downloadFileName,"w")
flag = True#默认可以下载
num = 0
while True:
#测试接收服务的信息
responseData = udpSocket.recvfrom(1024)
#print(responseData)
recvData,resip_port = responseData
#print("直接从服务器获取未加工的数据为:%s"%recvData)
#print("获取的ip和port是:"),
#print(resip_port)
#print("-"*30)
#opNum表示操作码,1上传,2下载,3数据包,4ACK,5ERR,(这里要么是3要么是5)
opNum = struct.unpack("!H",recvData[:2])
#packetNum表示块编号
packetNum = struct.unpack("!H",recvData[2:4])
#print(opNum)
print(packetNum[0])
if opNum[0] == 3:
num = num + 1
if num == 65536:
num = 0
if num == packetNum[0]:
f.write(recvData[4:])
num = packetNum[0]
ackData = struct.pack("!HH",4,packetNum[0])
udpSocket.sendto(ackData,resip_port)
if opNum[0] == 5:
print("没有这个文件,无法下载!")
flag = False
if len(recvData)<516 and packetNum != 1:
break
if flag == True:
f.close()
else:
os.unlink(downloadFileName)#如果没有这个文件,则删除创建的文件
udpSocket.close()
if __name__ == '__main__':
main()
经过测试小文件没有问题,过大的文件传输会有丢失,传输一个大小为128MB的文件,实际下载后只有76.3BM,造成的原因暂时没能解决