tftp协议给服务器上传数据,TFTP数据包格式,TFTP协议过程分析

六、Python实现TFTP协议

1、客户端下载文件参考程序

#coding=utf-8

#导包

import sys

import struct

from socket import *

#全局变量

g_server_ip = ‘’

g_downloadFileName = ‘’

#运行程序格式不正确

def run_test():

“判断运行程序传入参数是否有错”

global g_server_ip

global g_downloadFileName

if len(sys.argv) != 3:

print(“运行程序格式不正确”)

print(‘-’*30)

print(“tips:”)

print(“python3 tftp_download.py 192.168.1.1 test.jpg”)

print(‘-’*30)

exit()

else:

g_server_ip = sys.argv[1]

g_downloadFileName = sys.argv[2]

#print(g_server_ip, g_downloadFileName)

#主程序

def main():

run_test()

# 打包

sendDataFirst = struct.pack(‘!H%dsb5sb’%len(g_downloadFileName), 1, g_downloadFileName.encode(‘gb2312’), 0, ‘octet’.encode(‘gb2312’), 0)

# 创建UDP套接字

s = socket(AF_INET, SOCK_DGRAM)

# 发送下载文件请求数据到指定服务器

s.sendto(sendDataFirst, (g_server_ip, 69)) #第一次发送, 连接tftp服务器

downloadFlag = True #表示能够下载数据,即不擅长,如果是false那么就删除

fileNum = 0 #表示接收文件的序号

# 以二进制格式创建新文件

f = open(g_downloadFileName, ‘wb’)

while True:

#3. 接收服务发送回来的应答数据

responseData = s.recvfrom(1024)

#print(responseData)

recvData, serverInfo = responseData

# 解包

packetOpt = struct.unpack(“!H”, recvData[:2]) #操作码

packetNum = struct.unpack(“!H”, recvData[2:4]) #块编号

#print(packetOpt, packetNum)

# 接收到数据包

if packetOpt[0] == 3: #optNum是一个元组(3,)

# 计算出这次文件的序号,是上一次接收到的+1。

fileNum += 1

# 文件超过了65535 那么就又从0开始计数。

if fileNum == 65536:

fileNum = 0

# 包编号是否和上次相等

if fileNum == packetNum[0]:

f.write(recvData[4:]) #写入文件

fileNum = packetNum[0]

# 整理ACK的数据包

ackData = struct.pack(“!HH”, 4, packetNum[0])

s.sendto(ackData, serverInfo)

# 错误应答

elif packetOpt[0] == 5:

print(“sorry,没有这个文件!”)

downloadFlag = False

break

else:

print(packetOpt[0])

break

# 接收完成,退出程序。

if len(recvData) downloadFlag = True

print(“%s文件下载完毕!”%g_downloadFileName)

break

if downloadFlag == True:

f.close()

else:

os.unlink(g_downloadFileName) #没有下载的文件,就删除刚创建的文件。

#调用main函数

if __name__ == ‘__main__’:

main()

2、客户端上传文件程序

#coding=utf-8

# 导包

import sys

import struct

from socket import *

# 全局变量

g_server_ip = ‘’

g_uploadFileName = ‘’

#运行程序格式不正确

def run_test():

“判断运行程序传入参数是否有错”

global g_server_ip

global g_uploadFileName

if len(sys.argv) != 3:

print(“运行程序格式不正确”)

print(‘-’*30)

print(“tips:”)

print(“python3 tftp_upload.py 192.168.1.1 test.jpg”)

print(‘-’*30)

exit()

else:

g_server_ip = sys.argv[1]

g_uploadFileName = sys.argv[2]

#print(g_server_ip, g_uploadFileName)

#主程序

def main():

run_test()

# 打包

sendDataFirst = struct.pack(‘!H%dsb5sb’%len(g_uploadFileName), 2, g_uploadFileName.encode(‘gb2312’), 0, ‘octet’.encode(‘gb2312’), 0)

# 创建UDP套接字

s = socket(AF_INET, SOCK_DGRAM)

# 发送上传文件请求到指定服务器

s.sendto(sendDataFirst, (g_server_ip, 69)) #第一次发送, 连接tftp服务器

fileNum = 0 #表示接收文件的序号

# 以二进制格式打开文件

f = open(g_uploadFileName, ‘rb’)

# 第一次接收数据

responseData = s.recvfrom(1024)

# print(responseData)

recvData, serverInfo = responseData

#print(recvData)

#print(serverInfo)

# 解包

packetOpt = struct.unpack(“!H”, recvData[:2]) #操作码

packetNum = struct.unpack(“!H”, recvData[2:4]) #块编号

#print(packetOpt, packetNum)

if packetOpt[0] == 5:

print(“tftp服务器发生错误!”)

exit()

while True:

# 从文件中读取512字节数据

readFileData = f.read(512)

# 打包

sendData = struct.pack(‘!HH’, 3, fileNum) + readFileData

# 发送数据到tftp服务器

s.sendto(sendData, serverInfo) #第二次发给服务器的随机端口

# 接受服务器回传数据

recvData, serverInfo = s.recvfrom(1024)

#print(recvData)

# 解包

packetOpt = struct.unpack(“!H”, recvData[:2]) #操作码

packetNum = struct.unpack(“!H”, recvData[2:4]) #块编号

if packetOpt[0] == 5:

print(“tftp服务器发生错误!”)

exit()

if len(sendData) print(“%s文件上传成功!”%g_uploadFileName)

break

fileNum += 1

# 关闭文件

f.close()

# 关闭套接字

s.close()

#调用main函数

if __name__ == ‘__main__’:

main()

3、服务器参考程序

#coding=utf-8

# 导包

import sys

import struct

from socket import *

from threading import Thread

‘’‘

利用多线程的机制,来实现tftp服务器同时进行上传和下载功能。

’‘’

# 客户端上传线程

def upload_thread(fileName, clientInfo):

“负责处理客户端上传文件”

fileNum = 0 #表示接收文件的序号

# 以二进制方式打开文件

f = open(fileName, ‘wb’)

# 创建UDP套接字

s = socket(AF_INET, SOCK_DGRAM)

# 打包

sendDataFirst = struct.pack(“!HH”, 4, fileNum)

# 回复客户端上传请求

s.sendto(sendDataFirst, clientInfo) #第一次用随机端口发送

while True:

# 接收客户端发送的数据

responseData = s.recvfrom(1024) #第二次客户连接我随机端口

# print(responseData)

recvData, clientInfo = responseData

#print(recvData, clientInfo)

# 解包

packetOpt = struct.unpack(“!H”, recvData[:2]) #操作码

packetNum = struct.unpack(“!H”, recvData[2:4]) #块编号

#print(packetOpt, packetNum)

# 客户端上传数据

if packetOpt[0] == 3 and packetNum[0] == fileNum:

# 保存数据到文件中

f.write(recvData[4:])

# 打包

sendData = struct.pack(“!HH”, 4, fileNum)

# 回复客户端ACK信号

s.sendto(sendData, clientInfo) #第二次用随机端口发

fileNum += 1

if len(recvData) print(“用户”+str(clientInfo), end=‘’)

print(‘:上传’+fileName+‘文件完成!’)

break

# 关闭文件

f.close()

# 关闭UDP套接字

s.close()

# 退出上传线程

exit()

# 客户端下载线程

def download_thread(fileName, clientInfo):

“负责处理客户端下载文件”

# 创建UDP套接字

s = socket(AF_INET, SOCK_DGRAM)

fileNum = 0 #表示接收文件的序号

try:

f = open(fileName,‘rb’)

except:

# 打包

errorData = struct.pack(‘!HHHb’, 5, 5, 5, fileNum)

# 发送错误信息

s.sendto(errorData, clientInfo) #文件不存在时发送

exit() #退出下载线程

while True:

# 从本地服务器中读取文件内容512字节

readFileData = f.read(512)

fileNum += 1

# 打包

sendData = struct.pack(‘!HH’, 3, fileNum) + readFileData

# 向客户端发送文件数据

s.sendto(sendData, clientInfo) #数据第一次发送

if len(sendData) print(“用户”+str(clientInfo), end=‘’)

print(‘:下载’+fileName+‘文件完成!’)

break

# 第二次接收数据

responseData = s.recvfrom(1024)

# print(responseData)

recvData, clientInfo = responseData

#print(recvData, clientInfo)

#解包

packetOpt = struct.unpack(“!H”, recvData[:2]) #操作码

packetNum = struct.unpack(“!H”, recvData[2:4]) #块编号

#print(packetOpt, packetNum)

if packetOpt[0] != 4 or packetNum[0] != fileNum:

print(“文件传输错误!”)

break

# 关闭文件

f.close()

# 关闭UDP套接字

s.close()

# 退出下载线程

exit()

# main函数

def main():

# 创建UDP套接字

s = socket(AF_INET, SOCK_DGRAM)

# 解决重复绑定端口

s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)

# 绑定任意IP,端口号69

s.bind((‘’, 69))

print(“tftp服务器成功启动!”)

print(“正在运行中。。.”)

while True:

# 接收客户端发送的消息

recvData, clientInfo = s.recvfrom(1024) # 第一次客户连接69端口

#print(clientInfo)

# 解包

if struct.unpack(‘!b5sb’, recvData[-7:]) == (0, b‘octet’, 0):

opcode = struct.unpack(‘!H’,recvData[:2]) # 操作码

fileName = recvData[2:-7].decode(‘gb2312’) # 文件名

# 请求下载

if opcode[0] == 1:

t = Thread(target=download_thread, args=(fileName, clientInfo))

t.start() # 启动下载线程

# 请求上传

elif opcode[0] == 2:

t = Thread(target=upload_thread, args=(fileName, clientInfo))

t.start() # 启动上传线程

# 关闭UDP套接字

s.close()

# 调用main函数

if __name__ == ‘__main__’:

main()

调试可以通过Wireshark 软件进行调试,也可以打印传输数据信息进行调试!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值