用python写一个简单的TFTP服务器

用python写一个简单的TFTP服务器,练习python socket用法。 暂时只实现文件上传,思路很简单: 1.创建UDP接口; 2.监听69端口; 3.接收UDP数据; 4.解析TFTP协议报文,执行创建文件或写入文件;

#!python
#Simple TFTP Server
#蒋晓岗<kerndev@foxmail.com>

import os
import io
import sys
import time
import socket

def send_ack(s, addr, pid):
	pkt = b"\x00\x04" + pid
	s.sendto(pkt, addr)

def send_err(s, addr, code, reason):
	pkt = b"\x00\x05" + code.to_bytes(2, "big") + reason.encode("utf-8") + b"\x00"
	s.sendto(pkt, addr)
	#print(pkt.hex(" "))

#main
total = 0
processing = False
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("0.0.0.0",69))
s.settimeout(2)
print("TFTPD start...")
while(True):
	try:
		req = s.recvfrom(1024)
	except Exception as e:
		if(processing):
			processing = False
			fp.close()
			print("\nRecv file failed:", e)
	else:
		req_data = req[0]
		req_addr = req[1]
		#print("recv", len(req_data), "bytes from:", req_addr)
		if(req_data[0:2] == b"\x00\x02"):
			name = req_data[2:].split(b"\x00")[0].decode("utf-8")
			if(processing):
				print("\nRefused new file:", name, ", from:", req_addr)
				send_err(s, req_addr, 0x00, "server busy!")
			else:
				try:
					fp = open(name, "wb+")
				except Exception as e:
					print("Accept new file:", name, ", from:", req_addr, "failed!", e)
					send_err(s, req_addr, 0x03, "disk error!")
				else:
					print("Accept new file:", name, ", from:", req_addr, "OK")
					send_ack(s, req_addr, b"\x00\x00")
					processing = True
					total = 0
		if(req_data[0:2] == b"\x00\x03"):
			if not processing:
				send_err(s, req_addr, 0x04, "invalid session!")
			else:
				pid = req_data[2:4]
				buf = req_data[4:]
				total = total + len(buf)
				fp.write(buf)
				send_ack(s, req_addr, pid)
				print("Recv %d bytes" % total, end="\r")
				if(len(buf) < 512):
					processing = False
					fp.close()
					print("\nRecv file complete, total size:", total, "bytes")

使用Windows自带TFTP进行上传文件的测试。

程序运行结果: