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))
相关推荐
云计算DevOps-韩老师1 小时前
【网络云SRE运维开发】2024第52周-每日【2024/12/31】小测-计算机网络参考模型和通信协议的理论和实操考题
开发语言·网络·计算机网络·云计算·运维开发
小米先森2 小时前
04 文件IO
linux
小白爱电脑2 小时前
光纤收发器技术参数详解
运维·网络·光纤收发
summersneverdie3 小时前
Ubuntu执行sudo apt-get update失败的解决方法
linux·ubuntu
陈序缘3 小时前
PyTorch快速入门
人工智能·pytorch·python·深度学习·算法·机器学习
编程梦想家(大学生版)3 小时前
使用Python和OpenCV进行视觉图像分割
开发语言·python·opencv
hgdlip4 小时前
ip属地是看运营商吗还是手机
网络·tcp/ip·智能手机
M姐实验室4 小时前
分类模型评估利器-混淆矩阵
人工智能·python·矩阵·分类
ueanaIU潇潇子4 小时前
Linux系统安装es详细教程
linux·运维·elasticsearch
关关钧5 小时前
【Linux】信号处理
linux·运维·信号处理