TFTP实现 / TFTP Implement
目录
服务器建立步骤主要有:
(1) 设定服务器IP和端口号(常用69),建立socket并bind地址;
(2) 设定服务器工作目录;
(3) 建立主循环进行监听,根据收到的信息选择读/写模式;
(4) (建立新的线程及socket)执行上传下载操作;
(5) 下载操作: block number设置为1—打开需要下载的文件—进入循环—读取512byte数据—发送读取的数据—等待ACK报文(超时重发)—确认opcode—确认数据长度是否结束(结束则进行结束处理,并关闭文件)11—block number +1;
(6) 上传操作: block number 设置为0—发送ACK报文—block number +1—打开新的文件存储上传数据—进入循环—等待接收DATA报文—确认opcode—写入数据—发送ACK报文—确认数据长度是否结束(结束则进行结束处理,并关闭文件)—block number +1。
Note: 关于THTP_Helper 的 TFTP 的加解码过程请参考 TFTP 加解码部分
1 import importlib 2 from TFTP_Helper import * 3 import socket 4 from threading import Thread 5 6 7 class TFTPServer(): 8 def __init__(self): 9 ip = '127.0.0.1' 10 port = 69 11 address = (ip, port) 12 self.home_path = 'TFTPServerFile' 13 self.server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 14 self.server.bind(address) 15 16 def readRequest(self, file_name, addr): 17 print('<<< RRQ', ' === Read request, starting file %s downing to client' % file_name, end='') 18 sock_down = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 19 block_num = 1 20 try: 21 f = open(self.home_path + '\' + file_name, 'rb') 22 except: 23 # file no found, exit thread 24 print('=== File %s no found' % file_name) 25 exit() 26 while True: 27 down_data = f.read(512) # data is byte format 28 sock_down.sendto(TFTPData.encode(block_num, down_data), addr) 29 print('>>> DATA', block_num) 30 ack_msg, ack_addr = sock_down.recvfrom(1024) 31 print('<<< ACK ', block_num) 32 opcode, ack_block_num = TFTPAck.decode(ack_msg) 33 assert opcode == 4 and ack_block_num == block_num, 'Invalid ack message.' 34 if len(down_data) < 512: 35 block_num = 1 36 print('=== Transmission of %s completed' % file_name) 37 f.close() 38 exit() 39 block_num += 1 40 print('=== Close file') 41 f.close() 42 43 def writeRequest(self, file_name, addr): 44 print('<<< WRQ', ' === Write request, starting file %s uploading to server' % file_name) 45 sock_upload = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 46 block_num = 0 47 sock_upload.sendto(TFTPAck.encode(block_num), addr) 48 print('>>> ACK') 49 try: 50 f = open('TFTPServerFIle\Copy-'+file_name, 'wb') 51 except: 52 print('=== File "%s" no found' % file_name) 53 exit() 54 block_num += 1 55 while True: 56 recv_data, addr = sock_upload.recvfrom(1024) 57 opcode, block_num_recv, data = TFTPData.decode(recv_data) 58 print('<<< DATA') 59 if opcode != 3 or block_num != block_num_recv: 60 print('=== Error Opcode or Block Number') 61 # TODO: add error msg send and handle here 62 exit() 63 f.write(data) 64 sock_upload.sendto(TFTPAck.encode(block_num), addr) 65 print('>>> ACK') 66 if len(data) < 512: 67 # TODO: add transmission completed handle here 68 block_num = 1 69 print('=== File "%s" transmission completed' % file_name) 70 f.close() 71 exit() 72 block_num += 1 73 74 def server_run(self): 75 while True: 76 print('=== Waiting client') 77 msg, addr = self.server.recvfrom(1024) 78 print('<<< Receive a connection from client %s, msg is %s' % (addr, msg)) 79 opcode, file_name = TFTPReadWriteRequest.decode(msg) 80 cmdSelect = {1: Thread(target=self.readRequest, args=(file_name, addr)), 81 2: Thread(target=self.writeRequest, args=(file_name, addr))} 82 try: 83 cmdSelect[opcode].start() 84 except: 85 print('<<< Receive error opcode%s' % opcode) 86 raise ErrorOpcode 87 88 server = TFTPServer() 89 server.server_run()
客户端建立步骤主要有:
(1) 获取服务器ip和端口;
(2) 下载操作: 建立下载socket—发送RRQ下载请求—设置block number为1—新建文件存储下载数据—进入循环—等待接收DATA报文—确认opcode—写入数据—发送ACK报文—确认数据长度是否结束(结束则进行结束处理,并关闭文件)—block number +1;
(3) 上传操作: 建立上传socket—发送WRQ上传请求—等待ACK报文—设置block number为0—确认opcode—打开需要上传的文件—进入循环—读取数据—发送DATA报文—接收ACK报文—确认opcode—确认数据长度是否结束(结束则进行结束处理,并关闭文件)—block number +1;
1 from TFTP_Helper import * 2 import socket 3 4 5 class TFTPClient(): 6 def __init__(self): 7 server_ip = '127.0.0.1' 8 port = 69 9 self.address = (server_ip, port) 10 11 def readRequest(self, file_name): 12 sock_down = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 13 send_data = TFTPReadWriteRequest.encode('r', file_name) 14 sock_down.sendto(send_data, self.address) 15 block_num = 1 16 try: 17 f = open('TFTPClientFIlecopy-'+file_name, 'wb') 18 except: 19 print('--- File "%s" no found' % file_name) 20 exit() 21 while True: 22 recv_data, recv_addr = sock_down.recvfrom(1024) 23 print('<<< DATA', block_num) 24 opcode, block_num_recv, data = TFTPData.decode(recv_data) 25 if opcode != 3 or block_num != block_num_recv: 26 print('--- Opcode or Block Number Error') 27 # TODO: add error msg send and handle here 28 break 29 f.write(data) 30 sock_down.sendto(TFTPAck.encode(block_num), recv_addr) 31 print('>>> ACK ', block_num) 32 if len(data) < 512: 33 # TODO: add transmission completed handle here 34 block_num = 1 35 print('--- File "%s" transmission completed' % file_name) 36 f.close() 37 break 38 block_num += 1 39 40 def writeRequest(self, file_name): 41 sock_upload = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 42 send_data = TFTPReadWriteRequest.encode('w', file_name) 43 sock_upload.sendto(send_data, self.address) 44 print('>>> WRQ') 45 recv_data, addr = sock_upload.recvfrom(1024) 46 print('<<< ACK') 47 opcode, ack_block = TFTPAck.decode(recv_data) 48 block_num = 0 49 if opcode != 4 or ack_block != block_num: 50 print('--- Error Opcode or Block Number') 51 # TODO: add error msg send and handle here 52 exit() 53 try: 54 f = open('TFTPClientFIle\'+file_name, 'rb') 55 except: 56 print('--- File "%s" no found' % file_name) 57 exit() 58 block_num += 1 59 while True: 60 upload_data = f.read(512) 61 sock_upload.sendto(TFTPData.encode(block_num, upload_data), addr) 62 print('>>> DATA') 63 ack_msg, addr = sock_upload.recvfrom(1024) 64 print('<<< ACK') 65 opcode, ack_block_num = TFTPAck.decode(ack_msg) 66 assert opcode == 4 and ack_block_num == block_num, 'Invalid ack message.' 67 if len(upload_data) < 512: 68 # TODO: add transmission completed handle here 69 block_num = 1 70 print('--- File "%s" transmission completed' % file_name) 71 f.close() 72 break 73 block_num += 1 74 75 76 tftp = TFTPClient() 77 for file in ['downFile.py', 'downFile.docx', 'downFile.txt', 'downFile.zip']: 78 tftp.readRequest(file) 79 for file in ['uploadFile.py', 'uploadFile.docx', 'uploadFile.txt', 'uploadFile.zip']: 80 tftp.writeRequest(file)
相关阅读
1. TFTP 的基本理论
2. struct 模块