python实现简单tftp(基于udp)

  • tftp是基于udp的协议
  • 实现简单的tftp,首先要有tftp的协议图。
  • tftp默认接收端口为69,但每次有连接过来后,tftp会随机分配一个端口来专门为这个连接来服务。
  • 操作码:1.上传 2.下载 3.传数据 4.接收确认 5.错误码 

tftp服务器简单实现:

from threading import Thread
from socket import *
import struct

def upload(filename,user_ip,user_port):
    num = 0
    f = open(filename,'ab') 
    s_up = socket(AF_INET,SOCK_DGRAM)
    send_data_1 = struct.pack("!HH",4,num)
    s_up.sendto(send_data_1,(user_ip,user_port))  #第一次用随机端口发送

    while True:
        recv_data,user_info = s_up.recvfrom(1024)  #第二次客户连接我随机端口
        caozuohao_up,ack_num = struct.unpack('!HH',recv_data[:4])
        print(caozuohao_up,ack_num,num)
        if int(caozuohao_up) == 3 and ack_num == num :
            f.write(recv_data[4:])
            send_data = struct.pack("!HH",4,num)
            s_up.sendto(send_data,(user_ip,user_port)) #第二次我用随机端口发
            num = num + 1
            if len(recv_data) < 516:
                print(user_ip+'上传文件'+filename+':完成')
                f.close()
                exit()
     
def download(filename,user_ip,user_port):
    s_down = socket(AF_INET, SOCK_DGRAM)
    num = 0

    try:
        f = open(filename,'rb')
    except:
        error_data = struct.pack('!HHHb',5,5,5,num)
        s_down.sendto(error_data, (user_ip,user_port))  #文件不存在时发送
        exit()  #只会退出此线程

    while True:
        read_data = f.read(512)
        send_data = struct.pack('!HH',3,num) + read_data
        s_down.sendto(send_data, (user_ip,user_port))  #数据第一次发送
        if len(read_data) < 512:
            print('传输完成, 对方下载成功')
            exit()        
        recv_ack =  s_down.recv(1024)  #第二次接收
        caozuoma,ack_num = struct.unpack("!HH", recv_ack)
#        print(caozuoma,ack_num,len(read_data))
        num += 1
        if int(caozuoma) != 4 or int(ack_num) != num-1 :
            exit()
    f.close()

s = socket(AF_INET,SOCK_DGRAM)
s.bind(('',69))

def main():
    while 1:
        recv_data,(user_ip,user_port) = s.recvfrom(1024)  #第一次客户连接69端口
        print(recv_data, user_ip, user_port)
        if struct.unpack('!b5sb',recv_data[-7:]) == (0, b'octet', 0):
            caozuoma = struct.unpack('!H',recv_data[:2])
            filename = recv_data[2:-7].decode('gb2312')
            if caozuoma[0] == 1:
                print('对方想下载数据',filename)
                t = Thread(target = download, args = (filename,user_ip,user_port)) 
                t.start()           
            elif caozuoma[0] == 2:
                print('对方想上传数据',filename)
                t = Thread(target = upload, args = (filename,user_ip,user_port)) 
                t.start()           

if __name__ == '__main__':
    main()

上传数据简单实现:

#!/usr/bin/env python3
#coding=utf-8

import struct
from socket import *


server_ip = '192.168.119.157'
send_data_1 = struct.pack('!H8sb5sb',2,'王辉.jpg'.encode('gb2312'),0,b'octet',0)
s = socket(AF_INET,SOCK_DGRAM)
s.sendto(send_data_1,(server_ip,69)) #第一次发给服务器69端口

f = open('王辉.jpg','rb')

recv_data = s.recvfrom(1024) #第一次接收数据
rand_port = recv_data[1][1]
print()
ack_num = struct.unpack("!HH",recv_data[0][:4])
num = 0
while True:
    read_data = f.read(512)
    send_data = struct.pack('!HH',3,num) + read_data
    s.sendto(send_data,(server_ip,rand_port)) #第二次发给服务器的随机端口
    recv_data_2,userinfo = s.recvfrom(1024)
    print(recv_data_2)
    ack_num = struct.unpack('!H',recv_data_2[2:4])
    print(len(read_data),num,ack_num[0],rand_port)
    if len(read_data) < 512 or ack_num[0] != num :
        break
    num = num + 1

下载数据简单实现:

#!/usr/bin/env python3
#coding=utf-8

import struct
from socket import *

filename = 'test.jpg'
server_ip = '192.168.1.113'

send_data = struct.pack('!H%dsb5sb'%len(filename),1,filename.encode('gb2312'),0,'octet'.encode('gb2312'),0)
s = socket(AF_INET,SOCK_DGRAM)
s.sendto(send_data,(server_ip,69)) #第一次发送, 连接服务器69端口

f = open(filename,'ab')

while 1:
    recv_data = s.recvfrom(1024) #接收数据
    caozuoma,ack_num = struct.unpack('!HH',recv_data[0][:4]) #获取数据块编号
    rand_port = recv_data[1][1]  #获取服务器的随机端口

    if int(caozuoma) == 5:
        print('服务器返回: 文件不存在...')
        break
    print(caozuoma,ack_num,rand_port,len(recv_data[0]))

    f.write(recv_data[0][4:])
    if len(recv_data[0]) < 516:
        break
    
    ack_data = struct.pack("!HH",4,ack_num)
    s.sendto(ack_data,(server_ip,rand_port))  #回复ACK确认包

 

转载于:https://www.cnblogs.com/Erick-L/p/7144139.html

### 回答1: 很高兴为您服务!这是一段示例代码,希望能够帮助您: from socket import *# Create a UDP socket sock = socket(AF_INET, SOCK_DGRAM)# Bind the socket to the port server_address = ('localhost', 69) sock.bind(server_address)while True: # Receive the data data, address = sock.recvfrom(1024) # Send the response back sock.sendto(data, address)# Close the socket sock.close() ### 回答2: TFTP(Trivial File Transfer Protocol)是一种简单的文件传输协议,它常用于传输小文件,如配置文件或固件。 下面是一个使用Python语言编写的简单TFTP服务器的代码示例: ```python import socket import struct import os SERVER_PORT = 69 BUFFER_SIZE = 1024 def read_request(filename): # 读取并解析TFTP读请求 opcode = 1 mode = 'octet' packet = struct.pack('!H', opcode) + filename.encode('ascii') + b'\x00' + mode.encode('ascii') + b'\x00' return packet def send_file(filename, client_address): # 发送文件到客户端 try: file = open(filename, 'rb') block_number = 1 while True: data = file.read(BUFFER_SIZE) if not data: break packet = struct.pack('!HH', 3, block_number) + data client_socket.sendto(packet, client_address) block_number += 1 # 等待客户端确认 ack_packet, client_address = client_socket.recvfrom(BUFFER_SIZE) opcode, received_block = struct.unpack('!HH', ack_packet[:4]) if opcode != 4 or received_block != block_number: break file.close() except FileNotFoundError: error_packet = struct.pack('!HH', 5, 1) + b'File not found\x00' client_socket.sendto(error_packet, client_address) def main(): server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) server_socket.bind(('0.0.0.0', SERVER_PORT)) print('TFTP Server started.') while True: request_packet, client_address = server_socket.recvfrom(BUFFER_SIZE) opcode = struct.unpack('!H', request_packet[:2])[0] if opcode == 1: # 文件读请求 filename = request_packet[2:-8].decode('ascii') send_file(filename, client_address) server_socket.close() if __name__ == '__main__': main() ``` 这段代码创建了一个TFTP服务器,它监听69端口,并根据收到的读取请求发送文件到客户端。服务器首先解析收到的请求,然后打开相应的文件进行读取,将文件内容拆分成数据块,并通过UDP套接字将数据块发送给客户端。每发送完一个数据块,服务器都会等待客户端确认。同时,如果请求的文件不存在,服务器会发送错误消息给客户端。 请注意,该代码仅提供了基本的TFTP服务器功能,可能还有其他错误处理等功能需要进一步完善。 ### 回答3: 使用Python编写TFTP协议服务端的代码如下: ```python import socket import struct # 定义TFTP协议相关的常量 OPCODE_READ = 1 # 读请求操作码 OPCODE_DATA = 3 # 数据传输操作码 OPCODE_ACK = 4 # 确认操作码 BLOCK_SIZE = 512 # 数据块大小 # 定义服务器地址和端口号 SERVER_IP = '127.0.0.1' SERVER_PORT = 69 def main(): # 创建UDP套接字并绑定服务器地址和端口号 server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) server_socket.bind((SERVER_IP, SERVER_PORT)) print("TFTP server is running on {}:{}".format(SERVER_IP, SERVER_PORT)) while True: # 接收客户端的请求 data, client_address = server_socket.recvfrom(1024) opcode = struct.unpack('!H', data[:2])[0] if opcode == OPCODE_READ: handle_read_request(data, client_address, server_socket) elif opcode == OPCODE_ACK: handle_acknowledgement(data, client_address, server_socket) def handle_read_request(request, client_address, server_socket): # 获取文件名和传输模式 filename = request[2:request.index(0, 2)].decode('utf-8') mode = request[request.index(0, 2) + 1:-1].decode('utf-8') # 假设文件在当前目录下 filepath = "./" + filename try: # 打开文件并读取内容 with open(filepath, 'rb') as file: file_data = file.read() # 计算文件总块数 num_blocks = len(file_data) // BLOCK_SIZE + 1 # 发送数据块给客户端 for block_number in range(num_blocks): start_index = block_number * BLOCK_SIZE end_index = start_index + BLOCK_SIZE data_block = file_data[start_index:end_index] packet = struct.pack('!HH', OPCODE_DATA, block_number) + data_block server_socket.sendto(packet, client_address) except FileNotFoundError: # 文件不存在,发送错误消息给客户端 error_packet = struct.pack('!HH', 5, 1) + b'File not found' server_socket.sendto(error_packet, client_address) def handle_acknowledgement(ack, client_address, server_socket): received_block_number = struct.unpack('!H', ack[2:4])[0] # 接收到确认消息,根据块号判断是否传输完毕 if received_block_number == 0: print("File transfer completed.") else: print("Received ACK for block {}".format(received_block_number)) if __name__ == '__main__': main() ``` 以上代码实现了一个简单TFTP协议服务端,能够处理客户端的读请求,并将文件内容按照数据块的方式发送给客户端。服务端使用UDP套接字,通过解析收到的数据包来判断客户端的请求和确认消息,根据需要进行相应的处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值