第三阶段:【TFTP】

1. TFTP介绍(了解)

  1. TFTP:(Trivial File Transfer Protocol)简单文件传输协议

  2. 使用这个协议,就可以实现简单地文件下载,TFTP端口号是69
    在这里插入图片描述
    在这里插入图片描述

  3. TFTP介绍:

  • 当客户端接收到的数据⼩于516(2字节操作码+2个字节的序号+512字节数据) 时, 就意味着服务器发送完毕了 (如果恰好最后一次数据长度为516,会再发一个长度为0的数据包)

  • 构造下载请求数据:“1test.jpg0octet0”

    • import struct

    • cmb_buf = struct.pack(“!H8sb5sb”,1,b“test.jpg”,0,b“octet”,0)
      如何保证操作码(1/2/3/4/5)占两个字节?如何保证0占一个字节?

    • !H8sb5sb:“ ! ” 表示按照网络传输数据要求的形式来组织数据(占位的格式)
      H:表示将后面的 1 替换成占两个字节
      8s:相当于8个s(ssssssss)占8个字节
      b:占一个字节

  1. struct模块使用:
  • struct模块可以按照指定格式将Python数据转换为字符串,该字符串为字节流

  • struct模块中最重要的三个函数是pack(), unpack(), calcsize()

    • 按照给定的格式(fmt),把数据封装成字符串(实际上是类似于c结构体的字节流)

      pack(fmt, v1, v2, …)

    • 按照给定的格式(fmt)解析字节流string,返回解析出来的元组

      unpack(fmt, string)

    • 计算给定的格式(fmt)占用多少字节的内存
      calcsize(fmt)

  • struct.pack("!HH",4,p_num)

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

"""
编写tftp下载需求的 --- 客户端
"""
from socket  import  *
import struct

udpSocket = socket(AF_INET,SOCK_DGRAM)

# 构建下载请求(按照要求准备格式数据)
# 整体数据如:1bag.jpg0octet0
filename = 'bag.jpg'
server_ip = '192.168.2.119'
send_data = struct.pack('!H%dsb5sb'%len(filename),1,filename.encode(),0,'octet'.encode(),0)

# 创建一个空文件
f = open(filename,'ab')

#发送读写请求
udpSocket.sendto(send_data,(server_ip,69))

# 接收服务器端的数据包信息
message = udpSocket.recvfrom(1024)

# 查看接收的信息的格式:返回的是一个元组  (数据包的内容,(发送方ip,发送方端口号))
# print(message)

# 从数据包里边获取 【数据块 ack_num】的信息
caozuoma,ack_num = struct.unpack('!HH',message[0][:4])
print(caozuoma) #3
print(ack_num)  #1

# 额外:做一个异常处理    拿操作码判断作处理
if int(caozuoma)==5:
    print('您下载的文件不存在!!!')

f.close()
udpSocket.close()
"""
编写tftp下载需求的 --- 客户端
"""
from socket  import  *
import struct

udpSocket = socket(AF_INET,SOCK_DGRAM)

# 构建下载请求(按照要求准备格式数据)
# 整体数据如:1bag.jpg0octet0
filename = 'bag.jpg'
server_ip = '192.168.2.119'
send_data = struct.pack('!H%dsb5sb'%len(filename),1,filename.encode(),0,'octet'.encode(),0)

# 创建一个空文件
f = open(filename,'ab')

# 向服务器发送读写请求, 只是一次  服务器端服务的端口号为69
udpSocket.sendto(send_data,(server_ip,69))

# 要循环的接收服务器端返回来的数据包信息  和给服务器端发送确认包信息
while True:
    # 接收服务器端返回来的数据包信息
    message = udpSocket.recvfrom(1024)

    # 从数据包里边获取 【操作码caozuoma,数据块ack_num】的信息
    caozuoma, ack_num = struct.unpack('!HH', message[0][:4])

    # 获取服务器端为当前这个客户端服务的端口号
    rand_port = message[1][1]

    # 打印程序跑的次数  ,以及每次所涉及的内容   操作码  数据块编号  每次数据内容的长度,为客户端服务的端口号
    print('操作码:%d,  数据块编号:%d, 每次数据内容的长度:%d,为客户端服务的端口号:%d'%(caozuoma,ack_num,len(message[0]),rand_port))

    # 额外:做一个异常处理    拿操作码判断作处理
    if int(caozuoma) == 5:
        print('您下载的文件不存在!!!')
        break  #跳出循环

    # 向创建的空文件里面写数据
    f.write(message[0][4:])

    # 判断循环结束条件    用数据包的长度来判断
    if len(message[0])<516:
        print("文件写入完毕")
        break
    # 给服务器端发送确认包信息
    ack_data = struct.pack('!HH',4,ack_num)
    udpSocket.sendto(ack_data,(server_ip,rand_port))

f.close()
udpSocket.close()
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值