一、代码
操作码 | 功能 |
---|---|
1 | 读请求,即下载 |
2 | 写请求,即上传 |
3 | 表示数据包,即DATA |
4 | 确认码,即ACK |
5 | 错误 |
from socket import * import struct s=socket(AF_INET,SOCK_DGRAM) #创建一个udp的套接字 data=struct.pack("!H5sb5sb",1,b"1.png",0,b"octet",0) #按照TFTP数据包的格式,构造读写请求。"!"表示网络传输;H表示2个字节;s表示字符类;b表示 byte类型;数字表示重复几次。 #octet表示八进制,此处固定写法。 # b"字符串" 转化为byte s.sendto(data,("192.168.249.55",69)) #将构造的TFTP数据包发送到TFTP服务器上69端口。 fp=open("/home/python/tupian1.png","wb") #在本机上打开并建立一个新文件 while(True): data=s.recvfrom(1024) print("从ip号%s,端口号%d的主机接受到数据:"%(data[1][0],data[1][1])) #接收来的data为一个元组,data=(data[0],(data[1][0],data[1][1])),data[0]表示516个字节的数据报,后面的是服务器发送数据报的ip地址和端口号。 #接收的TFTP数据报大小为516个字节,其中前2个字节表示操作码,往后2个字节表示数据报序号,后面的512个字节表示数据报数据。 op_bl= struct.unpack("!HH",data[0][:4]) #解包操作,data[0]表示TFTP的516个字节,data[0][:4]表示操作码和块编号。 _data=data[0][4:] #data[0][4:] 表示数据包的数据,占512byte if(op_bl[0]==5): #当操作码等于5的时候,表示错误 print("出差错,差错码是%d,"%op_bl[1]) elif op_bl[0]==3: #当操作码等于3的时候,表示数据包 data_ack=struct.pack("!HH",4,op_bl[1]) #形成ACK,4表示操作码,op_bl[1]表示块编号 fp.write(_data) #将块数据部分写入新文档 if len(data[0]) < 516: #当数据包内容小于516时表示文件已经传输完毕 s.sendto(data_ack, ("192.168.249.55", data[1][1])) #将ACK回复服务器 break else: s.sendto(data_ack, ("192.168.249.55", data[1][1])) else: print("异常") fp.close() #关闭文档 s.close() #关闭套接字