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))
相关推荐
用户27784491049933 小时前
借助DeepSeek智能生成测试用例:从提示词到Excel表格的全流程实践
人工智能·python
JavaEdge在掘金5 小时前
ssl.SSLCertVerificationError报错解决方案
python
我不会编程5556 小时前
Python Cookbook-5.1 对字典排序
开发语言·数据结构·python
老歌老听老掉牙6 小时前
平面旋转与交线投影夹角计算
python·线性代数·平面·sympy
可乐加.糖6 小时前
一篇关于Netty相关的梳理总结
java·后端·网络协议·netty·信息与通信
满怀10156 小时前
Python入门(7):模块
python
无名之逆6 小时前
Rust 开发提效神器:lombok-macros 宏库
服务器·开发语言·前端·数据库·后端·python·rust
大丈夫立于天地间6 小时前
ISIS协议中的数据库同步
运维·网络·信息与通信
你觉得2057 小时前
哈尔滨工业大学DeepSeek公开课:探索大模型原理、技术与应用从GPT到DeepSeek|附视频与讲义下载方法
大数据·人工智能·python·gpt·学习·机器学习·aigc
cg50177 小时前
Spring Boot 的配置文件
java·linux·spring boot