Python之TFTP客户端下载

# -*-coding:utf-8 -*-
'''
tftp,操作码讲解:
读写请求: 操作码(2Bytes),文件名(nBytest),0(1Bytes),"octet"(5Bytes),0(1Bytes)
数据包:操作码(2Bytes),块编码(2Bytes),数据(512Bytes)
ACK:    操作码(2Bytes),快编码(2Bytes)
ERROP:  操作码(2Bytes),差错码(2Bytes),差错信息(nBytes),0(1Bytes)
1:读请求,即下载
2:写请求,即上传
3:表示数据包,即DATA
4:确认吗,即ACK
5:错误
'''
from socket import *
import struct
import os


def main():
    # 获取要下载的文档
    DownloadFileName = raw_input("请输入要下载的文档:")

    # 创建UDP套接字
    UdpSocket = socket(AF_INET, SOCK_DGRAM)

    # 协议规范,转换为网络大端格式
    RequestFileData = struct.pack("!H%dsb5sb" % len(DownloadFileName), 1, DownloadFileName, 0, 'octet', 0)

    # 目标地址
    SendAddr = ("192.168.5.1", 69)

    # UDP发送
    UdpSocket.sendto(RequestFileData, SendAddr)

    # 创建文件,写入文件
    f = open(DownloadFileName, 'w')

    # 定义一个变量,用于记录块编码
    num = 0

    # 定义一个变量,用于判断TFTP没有找到该文件时,删除空文件,默认在TFTP上有该文件
    File = True

    while True:
        # 用于接收tftp返回值
        ResponseData = UdpSocket.recvfrom(1024)
        # tffp返回值是以元组形式返回,且前面是数据,最后是服务端IP及PORT,且需要记录该IP及Port,用于反馈ACK
        RecvData, ServerInfo = ResponseData
        # 操作码,以元组形式返回
        OpNum = struct.unpack("!H", RecvData[:2])
        # 块编码,以元组形式返回
        PacketNum = struct.unpack("!H", RecvData[2:4])

        # 判断收到的操作码,如果为3,即为读模式
        if OpNum[0] == 3:
            num = num + 1
            # 当下载的数据过大,2字节已经不够表示块编码时,会从0开始重新计算
            if num == 65536:
                num = 0
            # 判断记录的块编码是否等于传输的块编码,防止数据混乱
            if num == PacketNum[0]:
                f.write(RecvData[4:])
                num = PacketNum[0]

            # 整理ACK的数据包,反馈给TFTP
            AckData = struct.pack("!HH", 4, PacketNum[0])
            UdpSocket.sendto(AckData, ServerInfo)
        # 返回的操作码等于5,报错
        elif OpNum == 5:
            print("没有找到该文件")
            File = False

        # 当TFTP返回值小于516时,表明数据已经传输到最后一次
        if len(RecvData) < 516:
            break

    # 判断文件是关闭还删除
    if File == True:
        # 默认在TFTP上找到该文件,状态一直未True,
        f.close()
    else:
        # 如果没有找到该文件,操作码会报错,返回5,由上面将File该为False,以下代码执行删除文件
        os.unlink(DownloadFileName)


if __name__ == "__main__":
    main()
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值