C#实现UDP数据包大文件分包传输和接收组包

作者:小菜 更新时间:2025-03-16 点击数:
简介:如果需要使用UDP传输较大数据,例如传输10M的图片,这突破了UDP的设计原则。

UDP的设计是基于"datagram",也就是它假设你发送的每个数据包都能包含在

【菜科解读】

如果需要使用UDP传输较大数据,例如传输10M的图片,这突破了UDP的设计原则。

UDP的设计是基于"datagram",也就是它假设你发送的每个数据包都能包含在单一的包内。

并且设定UDP数据包的最大长度受基础网络协议的限制。

UDP数据包的理论最大长度限制是 65535 bytes,这包含 8 bytes 数据包头和 65527 bytes 数据。

但如果基于IPv4网络传输,则还需减去 20 bytes 的IP数据包头。

则单一的UDP数据包可传输的数据最大长度为:

MaxUdpDataLength = 65535 - 8 - 20 = 65507 bytes

这就需要实现UDP包的分包传输和接收组包功能。

分包功能

1 ///

2 /// UDP数据包分割器 3 /// 4 public static class UdpPacketSplitter 6 /// 7 /// 分割UDP数据包 8 /// 9 ///

UDP数据包所持有的序号10 ///

被分割的UDP数据包11 ///

分割块的长度12 /// 13 /// 分割后的UDP数据包列表14 /// 15 public static ICollection Split(long sequence, byte[] datagram, int chunkLength)17 if (datagram == null)18 throw new ArgumentNullException("datagram");20 List packets = new List();22 int chunks = datagram.Length / chunkLength;23 int remainder = datagram.Length % chunkLength;24 int total = chunks;25 if (remainder > 0) total++;27 for (int i = 1; i 0)35 int length = datagram.Length - (chunkLength * chunks);36 byte[] chunk = new byte[length];37 Buffer.BlockCopy(datagram, chunkLength * chunks, chunk, 0, length);38 packets.Add(new UdpPacket(sequence, total, total, chunk, length));41 return packets;43 }

发送分包

1 private void WorkThread()

2 { 3 while (IsRunning) 5 waiter.WaitOne(); 6 waiter.Reset(); 8 while (queue.Count > 0)10 StreamPacket packet = null;11 if (queue.TryDequeue(out packet))13 RtpPacket rtpPacket = RtpPacket.FromImage(14 RtpPayloadType.JPEG, 15 packet.SequenceNumber, 16 (long)Epoch.GetDateTimeTotalMillisecondsByYesterday(packet.Timestamp),17 packet.Frame);19 // max UDP packet length limited to 65,535 bytes20 byte[] datagram = rtpPacket.ToArray(); 21 packet.Frame.Dispose();23 // split udp packet to many packets 24 // to reduce the size to 65507 limit by underlying IPv4 protocol25 ICollection udpPackets 26 = UdpPacketSplitter.Split(27 packet.SequenceNumber, 28 datagram, 29 65507 - UdpPacket.HeaderSize);30 foreach (var udpPacket in udpPackets)32 byte[] udpPacketDatagram = udpPacket.ToArray();33 // async sending34 udpClient.BeginSend(35 udpPacketDatagram, udpPacketDatagram.Length,36 packet.Destination.Address,37 packet.Destination.Port,38 SendCompleted, udpClient);43 }

接收组包功能

1 private void OnDatagramReceived(object sender, UdpDatagramReceivedEventArgs e)

2 { 3 try 5 UdpPacket udpPacket = UdpPacket.FromArray(e.Datagram); 7 if (udpPacket.Total == 1) 9 RtpPacket packet = new RtpPacket(udpPacket.Payload, udpPacket.PayloadSize);10 Bitmap bitmap = packet.ToBitmap();11 RaiseNewFrameEvent(12 bitmap, Epoch.GetDateTimeByYesterdayTotalMilliseconds(packet.Timestamp));14 else16 // rearrange packets to one packet17 if (packetCache.ContainsKey(udpPacket.Sequence))19 List udpPackets = null;20 if (packetCache.TryGetValue(udpPacket.Sequence, out udpPackets))22 udpPackets.Add(udpPacket);24 if (udpPackets.Count == udpPacket.Total)26 packetCache.TryRemove(udpPacket.Sequence, out udpPackets);28 udpPackets = udpPackets.OrderBy(u => u.Order).ToList();29 int rtpPacketLength = udpPackets.Sum(u => u.PayloadSize);30 int maxPacketLength = udpPackets.Select(u => u.PayloadSize).Max();32 byte[] rtpPacket = new byte[rtpPacketLength];33 foreach (var item in udpPackets)35 Buffer.BlockCopy(36 item.Payload, 0, rtpPacket, 37 (item.Order - 1) * maxPacketLength, item.PayloadSize);40 RtpPacket packet = new RtpPacket(rtpPacket, rtpPacket.Length);41 Bitmap bitmap = packet.ToBitmap();42 RaiseNewFrameEvent(43 bitmap, 44 Epoch.GetDateTimeByYesterdayTotalMilliseconds(packet.Timestamp));46 packetCache.Clear();50 else52 List udpPackets = new List();53 udpPackets.Add(udpPacket);54 packetCache.AddOrUpdate(55 udpPacket.Sequence, 56 udpPackets, (k, v) => { return udpPackets; });60 catch (Exception ex)62 RaiseVideoSourceExceptionEvent(ex.Message);64 } 实现,UDP,数据,包大,文件,分包,传输,和,接收,

【qq硬盘】高速传输,大容量存储,轻松备份,保护您的数据

专业的在线重装系统软件 全新设计 / 全新代码编写 / 全新支持所有机型 全新支持Window 11 安装 【qq硬盘】高速传输,大容量存储,轻松备份,保护您的数据简介:【qq硬盘】是一款高效的数据传输和存储工具,它提供了高速传输、大容量存储和轻松备份的功能,能够有效保护您的数据。

无论是个人用户还是企业用户,都可以通过【qq硬盘】轻松管理和保护自己的重要数据。

工具原料:系统版本:Windows、Mac、Android、iOS等多个操作系统版本品牌型号:根据用户需求,可选择不同品牌和型号的硬盘软件版本:最新版本为V2.0一、最新的天梯图排行榜【qq硬盘】提供了2023年最新的天梯图排行榜,用户可以通过查看排行榜了解当前最受欢迎和性能最好的硬盘产品。

排行榜根据性能、容量、价格等多个指标进行评估,为用户提供了选择参考。

二、推荐排名前几的产品根据最新的天梯图排行榜,我们推荐以下几款排名靠前的产品:1. 产品A:具有超高的传输速度和大容量存储空间,适用于大规模数据传输和备份。

2. 产品B:采用先进的数据保护技术,能够有效防止数据丢失和损坏。

3. 产品C:轻巧便携,适合移动办公和旅行使用,同时具备高速传输和大容量存储功能。

三、保护数据的意义和作用数据是现代社会的重要资产,保护数据对个人和企业都具有重要意义和作用:1. 防止数据丢失:通过备份和存储数据,可以避免因硬盘损坏、病毒攻击等原因导致数据丢失。

2. 提高工作效率:高速传输和大容量存储功能可以提高数据的读写速度,提升工作效率。

3. 保护隐私安全:通过加密和权限控制等功能,可以保护个人和企业的隐私安全。

四、未来的发展方向随着科技的不断进步,【qq硬盘】将继续发展和创新,提供更多更好的功能和服务。

未来的发展方向包括:1. 提升传输速度:通过采用更先进的传输技术,提高数据传输速度。

2. 扩大存储容量:随着数据量的不断增加,【qq硬盘】将提供更大的存储容量,满足用户的需求。

3. 强化数据安全:加强数据加密和安全控制,保护用户数据的安全性。

总结:【qq硬盘】是一款功能强大的数据传输和存储工具,通过高速传输、大容量存储和轻松备份的功能,保护用户的数据安全。

未来,【qq硬盘】将继续发展创新,提供更好的功能和服务。

《空间数据库索引建立》实验报告

1.认识空间数据库中数据的存放方式或存储结构;2.掌握空间数据库的格网索引、标题索引的建立方法;3.理解空间索引的功能和意义;4.加强学生面向对象程序设计的能力。

实验II:空间数据库的格网索引建立一、实验课时和类型:学时:8 实验类型:综合性二、实验目的:1.认识空间数据库中数据的存放方式或存储结构;2.掌握空间数据库的格网索引、标题索引的建立方法;3.理解空间索引的功能和意义;4.加强学生面向对象程序设计的能力。

三、适用专业:地理信息系统专业四、采用教材:教材:《计算机地图制图》艾自兴,龙毅编著 武汉大学出版社参考书:《地图学》 祝国瑞 编著 武汉大学出版社五、仪器与工具:P3以上配置计算机;VC++工具软件;实验地图数据。

六、实验原理与内容:本次实验为综合性实验,涉及《数字地图制图原理》、《计算机地图制图原理》、《地图数据库》等几门课程中所讲的内容。

七、实验数据说明1、 地图区域:武汉市文件名:武汉实习数据.usr2、分类代码:代码 名称30000 控制点10000 图廓点10001 铁路10003 汽渡虚线10004 主要道路20001 码头20002 铁路中转站20003 河流、湖泊20004 居民地3、代码说明:分类代码第一个字符为1,表示线目标;分类代码第二个字符为2,表示面目标。

4、控制点顺序:第一点:左上角 第二点:右上角第三点:右下角 第四点:左下角 控制点的理论值(人为规定x,y):第一点:12.50 37.40第二点:62.50 37.40第三点:62.50 82.40 采用仿射变换方法。

主要实验内容:1.读取数据2.仿射变换3.绘图显示4.建立定位索引 格网索引5.建立定性索引 标题索引6.将已建立的格网索引用于目标拾取功能的实现7.运用已建立的标题索引实现对象的属性查询八、实验步骤:第一;建立一个MapOfWuhan (MFC)工程,参数缺省。

第二;建立地图三要素:点、线、面。

点类包括对应点的X,Y坐标;线类包括线号(Xcode),线分类代码(Xflcode)以及组成线的点号数组(m_array);面类包括面号(Mcode),面分类代码(Mflcode)以及组成面的点号数组(m_array)。

第三;在读取数据时,要设计存储结构。

在Doc中要建立点类数组Array_dian,线类数组Array_xian,面类数组Array_mian,分别存放对应的点线面类目标。

一共有655组数据,读取的时候每组中的X,Y坐标存放到预先定义的点类对象中,若每组的分类代码为线类目标的分类代码,则把相应的线的分类代码存放到事先定义的线类对象的Xflcode中,把对应的组号存放到Xcode中,把组成线的一系列点类对象存放到线类对象的m_array中,最后把线类对象存放到对应的线类数组(Array_xian)中;面类也是如此。

这样,就完成了读取存储,即将不同类的对象存放到不同的类数组中。

第四;对数据进行仿射变换。

选择控制点中的1,2,3点,根据这三点的理论值和规定其在屏幕上的输出值求出仿射变换的未知系数a0,a1,a2,b0,b1,b2。

然后,顺序扫描线类数组Array_xian和 面类数组Array_mian,对不同的线类对象和面类对象的坐标值进行变换(X=a0*x+a1*y+a2;Y=b0*x+b1*y+b2)。

第五;当显示数据时,为了保证面状地物不压盖线状地物,首先要对面装地物进行显示,即顺序扫描面类数组Array_mian,根据数组中对象分类代码(Mflcode)的不同,将不同的对象进行着色填充并显示在屏幕上;然后再顺序扫描线类数组Array_xian,同样根据线分类代码(Xflcode)的不同,对不同对象规定不同的画笔并显示在屏幕上。

第六;建立格网索引首先要建立一个索引类Csuoyin,其中包括存放经过每个格网的对象的标志号码(即线号(Xcode)和面号(Mcode))的数组HLcode,然后再Doc中定义一个自己已规定行列号的格网索引类的数组HL[行号][列号]。

然后对格网进行初始化,按行顺序扫描每一个格网,在初始化每一个格网时,要顺序扫描线类数组Array_xian和面类数组Array_mian,判断当前对象是否在当前格网内部,若在当前格网内部,则将当前对象的标志码(即线号Xcode或面号Mcode)存放到当前格网对应的HLcode中,依次进行,直到扫描完毕,格网初始化完毕。

第七;生成格网索引。

首先要判断当前鼠标点击处所对应格网的行列号(行号=(当前点击点.Y-20)/20;列号=(当前点击点.X-60)/20),然后再顺序扫描当前格网所存放的对象,在扫描每一个对象时,都要扫描一次线类数组Array_xian和面类数组Array_mian,若当前格网对象的号码与线类或者面类数组对象的Xcode或是Mcode相同,则对线类或者是面类数组中的对象进行显示输出。

至此,格网索引完毕。

第八;建立一个定性索引的对话框,在对话框中加入一个EditBox,即文字输入窗口,在窗口中输入要查询的地物名称,点击确定即可将窗口中的内容存放到定性索引下预先定义的一个Char类型的数组Dx_shuzu中。

第九;在Doc中定义一个定性索引类型的对象Dx_dialog,然后顺序扫描线类数组Array_xian,若当前在对话框输入的内容与对应的线类地物名称匹配成功(即Strcmp( 对话框输入内容 , 线类地物名称 )==0),则根据当前线状地物的分类代码Xflcode,将当前地物输出显示在屏幕上;顺序扫描面类数组Array_mian,若在对话框中输入的内容与面状地物的名称匹配成功(即Strcmp( 对话框输入内容 , 面类地物名称 )==0),则根据面状地物的分类代码Mflcode,将当前面状地物输出显示在屏幕上,定性索引建立完毕。

第十;求出当前点击点所对应的格网行列号,然后将当前格网存放的对象一次取出,再求出当前点击点与每个对象的距离d,再求出d中的最小值dmin,若dmin 《,空间数据库索引建立,》,实验,报告,认识,

加入收藏
               

C#实现UDP数据包大文件分包传输和接收组包

点击下载文档

格式为doc格式

  • 账号登录
社交账号登录