8 TFTP代码详解 协议写在程序中

1.版本1:发送请求

# -*- coding:utf-8 -*-

import struct
from socket import *

#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))

  

2.版本2:回复ack

# -*- coding:utf-8 -*-

import struct
from socket import *

#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))



#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])

   

3.版本3:while True 循环

# -*- coding:utf-8 -*-

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))


    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])

        time.sleep(0.1)

if __name__ == '__main__':
    main()

4.版本4:跳出循环

# -*- coding:utf-8 -*-

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])

        time.sleep(0.1)

        if len(recvData)<516:
            break


if __name__ == '__main__':
    main()

5.版本5:优化版本,文件不存在

# -*- coding:utf-8 -*-

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()

6.版本6:第二种参考程序

#coding=utf-8

from socket import *
import struct
import sys

if len(sys.argv) != 2:
    print('-'*30)
    print("tips:")
    print("python xxxx.py 192.168.1.1")
    print('-'*30)
    exit()
else:
    ip = sys.argv[1]

# 创建udp套接字
udpSocket = socket(AF_INET, SOCK_DGRAM)

#构造下载请求数据
cmd_buf = struct.pack("!H8sb5sb",1,"test.jpg",0,"octet",0)

#发送下载文件请求数据到指定服务器
sendAddr = (ip, 69)
udpSocket.sendto(cmd_buf, sendAddr)

p_num = 0

recvFile = ''

while True:
    recvData,recvAddr = udpSocket.recvfrom(1024)

    recvDataLen = len(recvData)

    # print recvAddr # for test

    # print len(recvData) # for test

    cmdTuple = struct.unpack("!HH", recvData[:4])

    # print cmdTuple # for test

    cmd = cmdTuple[0]
    currentPackNum = cmdTuple[1]        

    if cmd == 3: #是否为数据包

        # 如果是第一次接收到数据,那么就创建文件
        if currentPackNum == 1:
            recvFile = open("test.jpg", "a")

        # 包编号是否和上次相等
        if p_num+1 == currentPackNum:
            recvFile.write(recvData[4:]);
            p_num +=1
            print '(%d)次接收到的数据'%(p_num)

            ackBuf = struct.pack("!HH",4,p_num)

            udpSocket.sendto(ackBuf, recvAddr)
        # 如果收到的数据小于516则认为出错
        if recvDataLen<516:
            recvFile.close()
            print '已经成功下载!!!'
            break

    elif cmd == 5: #是否为错误应答
        print "error num:%d"%currentPackNum
        break

udpSocket.close()
原文地址:https://www.cnblogs.com/venicid/p/7994995.html