当前位置: 首页 > article >正文

udp分片报文发送和接收

读文件通过udp分片发送的目的端:(包含错误的分片包)

#!/usr/bin/python
# -*- coding: utf-8 -*-

#python send_100frag_file.py -p 55432 -f snatdownload


import argparse
import logging

from scapy.all import *

 # Define the maximum size of a packet
MAX_SIZE = 65500
 # Define the IP addresses and ports
src_ip = '11.0.0.1'
dst_ip = '11.0.0.2'
src_port = 12345
dst_port = 54321
 # Define the payload data
payload_data = 'A' * (MAX_SIZE - 20 - 8)
payload_data = 'A' * MAX_SIZE
# Create the IP header


# 创建参数解析器对象
parser = argparse.ArgumentParser(description="UDP数据接收脚本,可指定端口号和发送数据的文件名: python send_100frag_file.py -p 55432 -f snatdownload")

# 添加端口号参数,指定参数名为port,类型为整数,帮助信息为指定接收UDP数据的端口号,默认值设为9999
parser.add_argument('-p', '--port', type=int, help="指定接收UDP数据的端口号", default=9999)

# 添加文件名参数,指定参数名为filename,类型为字符串,帮助信息为指定保存接收到数据的文件名,默认值设为'received_data.data'

parser.add_argument('-f', '--filename', type=str, help="指定发送数据的文件名", default='input_data.data')
parser.add_argument('-i', '--ipid', type=int, help="指定ip id", default=11111)


# 解析命令行参数
args = parser.parse_args()

# 获取解析后的端口号和文件名
port = args.port
filename = args.filename
ipid = args.ipid

ip_header = IP(src=src_ip, dst=dst_ip, id = ipid)
 # Create the UDP header
#udp_header = UDP(sport=src_port, dport=dst_port+int(sys.argv[1]))
udp_header = UDP(sport=src_port, dport=port)
 # Combine the headers and payload

# 获取文件大小,用于后续判断是否发送完成
file_size = os.path.getsize(filename)
sent_size = 0

# 以二进制模式打开文件,方便处理各种类型的文件
with open(filename, 'rb') as file:
    while True:
        packet = None
        # 每次读取1024字节的数据块,可根据实际网络情况和文件大小调整这个值
        payload_data = file.read(MAX_SIZE)
        if not payload_data:
            break
        # 发送消息,需将消息编码为字节类型,因为网络传输的数据是字节流形式
        
        ip_header = IP(src=src_ip, dst=dst_ip, id = ipid)
        packet = ip_header / udp_header / payload_data
        fragments = fragment(packet, fragsize=656)
        for i, frag in enumerate(fragments):
            print('Fragment ' + str(i+1) + ': ' + str(len(frag)) + ' bytes')
            #print(fragment.show())
            if i < len(fragments) - 0:
                send(frag, verbose=False)
            if i >= 50:
                frag[IP].flags=0
                send(frag, verbose=False)                
        
        ipid += 1
        sent_size += len(payload_data)
        print("发送 {} 字节, 已发送 {} 字节,共 {} 字节".format(len(payload_data), sent_size, file_size))
        

end_marker = "END".encode('utf-8')
packet = ip_header / udp_header / end_marker
send(packet, verbose=False)
print("发送结束标志,发送结束")

接收指定端口收到的udp报文保存到本地文件,通过比较发送文件和接收文件的内容测试中间转发设备是否正确完整的处理了分片和重组:

#!/usr/bin/python
# -*- coding: utf-8 -*-

#python recv_dgram.py  -p 55432 -f my_data.txt

import socket
import argparse
import logging

# 创建参数解析器对象
parser = argparse.ArgumentParser(description="UDP数据接收脚本,可指定端口号和保存数据的文件名: python recv_dgram.py  -p 55432 -f my_data.txt")

# 添加端口号参数,指定参数名为port,类型为整数,帮助信息为指定接收UDP数据的端口号,默认值设为9999
parser.add_argument('-p', '--port', type=int, help="指定接收UDP数据的端口号", default=9999)

# 添加文件名参数,指定参数名为filename,类型为字符串,帮助信息为指定保存接收到数据的文件名,默认值设为'received_data.data'
parser.add_argument('-f', '--filename', type=str, help="指定保存接收到数据的文件名", default='received_data.data')

# 解析命令行参数
args = parser.parse_args()

# 获取解析后的端口号和文件名
port = args.port
file_name = args.filename

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

# 绑定本地地址和端口,这里假设绑定到本地所有可用地址(空字符串)的9999端口,你可以按需修改
local_address = ('', port)
udp_socket.bind(local_address)
udp_socket.settimeout(5)  # 设置超时时间为5秒

# 以二进制写入模式打开文件,方便处理各种类型的数据(文本、二进制等)
tot_len = 0
with open(file_name, 'wb') as file:
    while True:
        try:
            # 接收数据报,设置缓冲区大小为1024字节,可根据实际情况调整大小
            udp_socket.settimeout(5)  # 设置超时时间为5秒
            data, sender_address = udp_socket.recvfrom(65530)
            if not data:
                break
            if len(data) == 3 and data.decode('utf-8') == "END":
                logging.info("完成接收")
                print("完成接收")
                break
            tot_len += len(data)
             # 将接收到的数据写入文件
            file.write(data)
            print("从 {}接收到{}字节, total length: {}".format(sender_address, len(data), tot_len))

        except socket.timeout:
            logging.info("接收超时,可能暂时没有消息到达")
            continue
        except socket.error as e:
            print("接收UDP数据报时出错: {}".format(e))
            break

# 关闭套接字
udp_socket.close()
print("已成功将接收到的UDP数据报保存到 {} 文件中。".format(file_name))


http://www.kler.cn/a/460374.html

相关文章:

  • Java-多种方法实现多线程计数
  • 标准库以及HAL库——按键控制LED灯代码
  • LLM(十二)| DeepSeek-V3 技术报告深度解读——开源模型的巅峰之作
  • 【第二部分--Python之基础】03 容器类型的数据
  • 接口测试Day04-postman生成测试报告ihrm项目
  • Fedora安装docker
  • 经典排序算法:冒泡排序与选择排序
  • List排序的方法
  • JVM和异常
  • 【华为OD-E卷 - 机房布局 100分(python、java、c++、js、c)】
  • Edge如何获得纯净的启动界面
  • XIAO Esp32 S3 轻松发送 HTTP 请求,打造智能物联网应用
  • 优化咨询行业团队协作:通过有效的项目管理工具实现高效协作
  • 爬虫代码中如何添加异常处理?
  • torch.nn.Linear(p_input, p_output,bias)
  • 2024Jinger的前端学习内容总结——前端学习路线(超全)
  • 使用 Python 和 LabelMe 实现图片验证码的自动标注
  • 【ArcGISPro/GeoScenePro】检查多光谱影像的属性并优化其外观
  • Spring Boot 3 文件上传、多文件上传、大文件分片上传、文件流处理以及批量操作
  • WPF系列五:图形控件Ellipse
  • log4j2的Strategy、log4j2的DefaultRolloverStrategy、删除过期文件
  • 自己编写甘特图的绘制程序
  • golang 熔断限流降级
  • 商汤C++开发面试题及参考答案
  • 【postgresql 物化视图】自动刷新物化视图2种方法
  • order by语句执行顺序