victory的博客

长安一片月,万户捣衣声

0%

网络编程 | 使用tftp从服务器下载文件到客户端

使用tftp协议从服务器下载文件到客户端

Code

import struct
from socket import *
import time
import os

def main():


    #0. 获取要下载的文件名字:
    downloadFileName = raw_input("请输入要下载的文件名:")    

    #1.创建socket
    udpSocket = socket(AF_INET, SOCK_DGRAM)

    requestFileData = struct.pack("!H%dsb5sb"%len(downloadFileName), 1, downloadFileName, 0, "octet", 0)

    #2. 发送下载文件的请求
    udpSocket.sendto(requestFileData, ("192.168.119.215", 69))

    flag = True #表示能够下载数据,即不擅长,如果是false那么就删除
    num = 0
    f = open(downloadFileName, "w")

    while True:
        #3. 接收服务发送回来的应答数据
        responseData = udpSocket.recvfrom(1024)

        # print(responseData)
        recvData, serverInfo = responseData

        opNum = struct.unpack("!H", recvData[:2])

        packetNum = struct.unpack("!H", recvData[2:4])

        print(packetNum[0])

        # print("opNum=%d"%opNum)
        # print(opNum)

        # if 如果服务器发送过来的是文件的内容的话:
        if opNum[0] == 3: #因为opNum此时是一个元组(3,),所以需要使用下标来提取某个数据
            

            #计算出这次应该接收到的文件的序号值,应该是上一次接收到的值的基础上+1
            num = num + 1

            # 如果一个下载的文件特别大,即接收到的数据包编号超过了2个字节的大小
            # 那么会从0继续开始,所以这里需要判断,如果超过了65535 那么就改为0
            if num==65536:
                num = 0

            # 判断这次接收到的数据的包编号是否是 上一次的包编号的下一个
            # 如果是才会写入到文件中,否则不能写入(因为会重复)
            if num == packetNum[0]:
                # 把收到的数据写入到文件中
                f.write(recvData[4:])
                num = packetNum[0]

            #整理ACK的数据包
            ackData = struct.pack("!HH", 4, packetNum[0])
            udpSocket.sendto(ackData, serverInfo)

        elif opNum[0] == 5:
            print("sorry,没有这个文件....")
            flag = False

        # time.sleep(0.1)

        if len(recvData)<516:
            break

    if flag == True:
        f.close()
    else:
        os.unlink(downloadFileName)#如果没有要下载的文件,那么就需要把刚刚创建的文件进行删除

if __name__ == '__main__':
    main()