• Tftp文件传输服务器(基于UDP协议)


    一个简单的UDP服务端与客户端

    服务端: 

     1 from socket import *
     2 #创建套接字
     3 udp_server = socket(AF_INET,SOCK_DGRAM)
     4 
     5 msg_server = ("",8877)
     6 #绑定ip地址和端口
     7 udp_server.bind(msg_server)
     8 
     9 while True:
    10     #接受消息,注意此处用的是   recvfrom()
    11     msg_client = udp_server.recvfrom(1024)
    12 
    13     print("新客户端已连接--->>>")
    14 
    15     if len(msg_client) != 0:
    16         #msg_client中有两个值,第一个表示收到的消息的内容,第二个表示客户端的IP地址和端口的信息
    17         print("%s:%s" % (msg_client[1], msg_client[0].decode("utf-8")))
    18     else:
    19         break
    20 
    21 udp_server.close()

    客户端:

    from socket import *
    
    sock = socket(AF_INET,SOCK_DGRAM)
    
    addr_msg = ("192.168.1.104",8877)
    #连接服务端
    sock.connect(addr_msg)
    
    while True:
        msg_send = input("请输入要发送的信息:")
        if msg_send =='q':
            break
        #注意此处用的是sendto()     其中第一个参数表示要发送的消息的内容,第二个参数表示服务端的IP地址和端口的元组
        sock.sendto(msg_send.encode("utf-8"),addr_msg)
    
    sock.close()

    基于UDP的tftp文件传输

    客户端:

     1 from socket import *
     2 import struct
     3 import os
     4 
     5 def main():
     6     file_name = input("请输入要下载的文件名:")
     7     #建立一个UDP的套接字
     8     udpsocket = socket(AF_INET,SOCK_DGRAM)
     9     #创建一个tftp的下载请求  H表示第一个参数占用两个字节,d表示对应的参数为bite类型
    10     #  %ds 表示文件名占用的字符个数,如后面的octet占用了5个字符,所以写成5s
    11     #  octet是tftp传输的一种模式,它决定了传输数据的格式,还有其他的几种tftp传输的模式
    12     #构造包使用的是struck中的pack   ,其中的 H 表示使参数占用两个字节
    13     request_header = struct.pack("!H%dsb5sb"%len(file_name),1,file_name.encode('utf-8'),0,b"octet",0)
    14     server_msg = ("192.168.0.100",69)
    15     #发送一个下载文件的请求
    16     udpsocket.sendto(request_header,server_msg)
    17 
    18     # 这里必须以wb的格式打开文件,否则文件不能正常显示
    19     f = open(file_name,"wb")
    20 
    21     #  num表示的是数据块的编号,这里使得其初始值为0
    22     num = 0
    23     #此处建立一个标记,以确认传输过程中没发生错误
    24     mask = True
    25 
    26     while True:
    27         # 接收服务端发来的数据包
    28         response_data = udpsocket.recvfrom(1024)
    29         recv_data, server_info  = response_data
    30 
    31         # 此处用struct中的unpack来解包  H 表示数据占用两个字节长度
    32         # 这里的前两个字节中存储的是操作码
    33         operation_num = struct.unpack("!H",recv_data[:2])
    34         # 这里的第三个和第四个字节中存储的是数据块的编号
    35         package_num = struct.unpack("!H",recv_data[2:4])
    36         print(package_num[0])
    37 
    38         # 操作码为3时表示接收到的信息是服务端收到响应而发给客户端的数据包
    39         if operation_num[0] == 3:
    40             #这一次收到的值应该是在上一次收到的值的基础上加上一后的结果
    41             num =num + 1
    42             #此处表示一旦num的值超过了它2个字节所表示的值的范围,则让它从0开始再来重复一遍(主要是因为操作码只能占2个字节)
    43             if num == 65535:
    44                 num = 0
    45             # 进行块编号的确认
    46             if num == package_num[0]:  #此处取下标是因为此时的package_num表示的是一个元组,而块编号是元组中的第一个数据
    47                 # 将收到的具体数据写入到文件中
    48                 f.write(recv_data[4:])
    49                 #块编号的确认每次都要在之前的值上加1
    50                 num = package_num[0]
    51             #构造一个响应包  操作码为4   发送的数据就是加上1后的块编号
    52             ack_data = struct.pack("!HH",4,package_num[0])
    53             #发送响应包
    54             udpsocket.sendto(ack_data, server_info)
    55 
    56         elif operation_num[0] == 5:
    57             print("Error!")
    58             #若发生错误信息,则将标记的值改成False , 以便后续操作删除这个文件
    59             mask = False
    60             f.close()
    61 
    62         # 一个数据包的最大长度为 4+512 = 516 位,如果数据包小于这个数值,则表明这已经是最后一次的数据传输了
    63         if len(recv_data) < 516:
    64             print("Finish!")
    65             break
    66     # mask标记的值为True则表示文件传输的过程中没有发生错误,就将本地接收到的文件关闭保存
    67     if mask == True:
    68         f.close()
    69 
    70     else:
    71         # mask标记的值为False则表示文件传输的过程中出现了错误信息,则将已经接收到的文件删除
    72         os.remove(file_name)
    73 
    74 if __name__ == "__main__":
    75     main()

    至于服务端可以用 tftpd32 这个软件来模拟实现

    关于TFTP协议

    TFTP协议是一种基于UDP的小型文件传输协议,它不具备FTP的许多功能

    TFTP的端口号为69

    一个数据包在接受的过程中最大长度为512+2+2=516字节,所以当它的长度小于516字节时便可以判断出这是最后一次的数据传输

    上面构造数据包时使用的H的意思是,让它所代表的参数占用两个字节的长度,从而使数据包符合TFTP协议的要求

  • 相关阅读:
    java中this关键字
    java继承
    java super关键字
    java String类型存储详解
    java四种访问权限修饰符
    C/C++语言void及void指针深层探索【转】
    Linux Epoll介绍和程序实例【转】http://blog.csdn.net/sparkliang/article/details/4770655
    服务器与wp7的socket通信【转】 http://www.cnblogs.com/linzheng/archive/2011/06/21/2086456.html
    android关于socket编程,以聊天为例【转】http://hi.baidu.com/yaoyuanhuajx/item/9b93d7565f315ba9acc857d7
    Tesseract 3 语言数据的训练方法【转】http://blog.csdn.net/dragoo1/article/details/8439373
  • 原文地址:https://www.cnblogs.com/hgzero/p/8965079.html
Copyright © 2020-2023  润新知