一,TFTP协议介绍
TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户端与服务器之间进行简单文件传输的协议
特点:简单,
占用资源少
适合传递小文件
适合在局域网进行传递
端口号为69
基于UDP实现
二,TFTP协议原理:
1.客户端发送一个读写请求(读为下载,写为上传)给服务器,服务器接收请求的默认端口是69,注意此端口只是用于接收请求数据
2.服务器接到请求数据后,解析其中的请求数据,然后在本地目录下找是否有此文件名,若没有此文件名,将会返回一个错误信息给客户端,若有此文件,将会多次发送文件中的512B大小的数据给客户端,直到发送完毕。服务器发送错误信息以及发送文件数据的端口都是找一个随机端口。
3.由于是UDP协议,所以文件传输数据不稳定。为了使其稳定,客户端口每接收到服务器发送来的文件数据的时候,都要给服务器发送一个ACK确认信息,服务器接到ACK确认信息后,再发送剩下的文件数据。
三,TFTP数据包格式:
前面讲了发送数据,那发送的数据格式是什么呢,总不能发送‘I want to download test.jpg’给服务器,人家就会给你发送吧,在应用层上,TFTP自己也有自己的协议,其中发送数据的格式就是上面的图片中的格式。
操作码:写1表示读,2表示写,3表示是一个数据包,4表示是一个ACK,5表示是一个ERROR
块编号:由于服务器无法一次性将文件传输过去,所以是每次发送512B,在发送的时候会给每个数据包打上一个编号(如:1,2,3,4,5....),防止出错。
octet:这是一个固定的,是TFTP里面发送请求的模式叫做octet。
四,数据的packt和unpack
若想要发送一个请求数据,我们需要给这个数据打包一下,就比如你在网上买了一个手机,商家肯定首先会用一个盒子把它打包好,再后再去运输。你接到快递后,也会拆开包装吧。这就是需要pack和unpack的原因所在了。
五,客户端
客户端口代码:
import socket
import struct
#config配置信息
ip = '192.168.1.105'
port = 69
#构建客户端请求对象
client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
#构造发送请求数据
request = struct.pack('!H8sb5sb',1,b'test.jpg',0,b'octet',0)
client.sendto(request,(ip,port))
pack_num = 0
f = open('test.jpg','wb+')
while True:
#接收服务器的数据信息
recv = client.recvfrom(1024)
recvData = recv[0]
serverinfo = recv[1]
print(len(recvData))
operateTupe = struct.unpack('!HH',recvData[:4])
operate_code = operateTupe[0] #代表操作码
data_num = operateTupe[1] #代表块编号
print('块编号:',data_num)
if operate_code==3: #判断此为数据包
if pack_num+1==data_num:
f.write(recvData[4:])
pack_num+=1
print('第%s次接收到数据'%pack_num)
ack = struct.pack('!HH',4,pack_num)
client.sendto(ack,serverinfo)
if len(recvData)<516: #最后一次的数据包
f.close()
print('下载完成')
break
elif operate_code==5: #判断此为错误信息包
print('下载出错,错误包:%s'%data_num)
break
client.close()
结果: