Socket服务器端接收多个目标数据,每个客户端数据都分包发送,接收时如何分别拼接,求实现方案

时间:2023-01-24 05:56:32

Socket服务器端接收多个目标数据(大量用户)  UDP方式

客户端发送数据时会分包发送,大概结构

typedef struct
{
BYTE bPacketNum; // 总包数
BYTE bPacketNo; // 当前包ID
BYTE bRespond_ID; //确认是否收到
}NMVS_PACKHEAD_NEW_T;

包头后面是数据,每个包1024的长度

我收到包后,要把每个1024里的数据拷贝出来 拼接到一起, 这个没问题

现在问题来了, 多路数据,我可能先收到A 用户的 第3个包, 再收到B用户的 第4个包

那当多用户的时候,这个如何进行拼接,有什么实现方案,欢迎大虾来指点下,100 分奉送!!!

链表貌似不行,效率太低,因为用户大,可能几万用户甚至更多。。。

欢迎大家来讨论指点交流~~~~

19 个解决方案

#1


来个大虾 UP 一下呀

#2


参考RTP协议

#3


楼主说的大量用户有多大,几万个?可以考虑每个用户一个线程分别处理,单个用户根据数据id拼凑

#4


引用 3 楼 xumaojun 的回复:
楼主说的大量用户有多大,几万个?可以考虑每个用户一个线程分别处理,单个用户根据数据id拼凑

一个用户一个线程在这种几万个用户的情况下不行吧,可以考虑开个线程池,LZ这种需求用std::vector完全没问题,单单存储数据的话,自动增长完全满足你的要求

#5


谢谢2楼,我仔细看看 RTP协议 协议

3楼的方案肯定不行,每个用户一个线程。。。再好的服务器也扛不住


谢谢4楼,我研究研究

#6


关于 我这个问题,有个比较重要的地方, 就是我收到的每个包都不是独立的, 是需要把同一系列的 拼接到一起 才可以解析 存储

同一客户端传一次可能会传N 个包,这N个包需要 拼接到一起才有用

所以现在就出现这个问题,如何 分别拼接,存储

#7


就算是千兆的网,你这么大的数据量也会丢包的把?
几万个连接,还敢用udp协议。。。

#8


还是换成tcp的把
用不同的标志头

#9


引用 7 楼 nice_cxf 的回复:
就算是千兆的网,你这么大的数据量也会丢包的把?
几万个连接,还敢用udp协议。。。



对于我丢包这个,我每个包都有 确认机制,  收到包后会给 客户端回传收到的 标志, 客户端一系列包发送完后,会检查哪些没有收到确认,然后重发

#10


每个包定义一个包序列号,服务端接收到所有包后再根据序列号排序,好像那些p2p软件是这样处理的

#11


参考protobuf

#12


引用 11 楼 zhao4zhong1 的回复:
参考protobuf


protobuf ?  详解?

#13


额,还没找到好方法。。。。。主要是 不知道 如何去高效率存储

#14


UDP协议就是一个无序的
可参考UDT

#15


接收其实不是问题,问题 是收到后,如何 分别拼接多用户 发过来的 数据包~

#16


1. UDP 的数据包通过 recvfrom 能得到对端的 IP 和 端口 (sockaddr 类型),基于这个类型的数据结构封装一个类,实现 ‘== ’ 操作,可以用 ACE_INet_Addr
2. 为每个通信对端建立一个控制快,用于缓冲接受的数据,比如:
   struct CLIENT_CB
   {
       uint32_t recv_mask;
       NMVS_PACKHEAD_NEW_T *data[MAX_RECV_MSG];
       int fd;
   }
   'recv_mask' 记录的是数组的哪一个元素上已经存储了了接收的数据,它的数据类型由 MAX_RECV_MSG 而定。如果你只想为每个用户缓冲32个数据包就用 uint32_t,以此类推。
   'fd' 是为了将接收数据转存而打开的文件 (可选)

3. 建立一个关联数据容器,(比如 hash_map<ACE_INet_Addr, CLIENT_CB>). 这样一来,都应发送端的数据就能对应地记录在上述的数据结构当中,每次记录后检查掩码位,如果接收连续的 N 个数据包,可以考虑将其转存到磁盘上,为后续接收腾出内存空间,这时需要进行文件 I/O, 更改掩码值并对数组的元素进行移位操作,由于数组的元素有个数上限,所以这个开销是可以控制的。

4. 这个方案有效性前提是,因为网络延迟导致 UDP 包接收的无序范围是在可接受的范围内。在选择 32 位掩码的时候,假设你在等待前10个包到来的时候来了序号为 11 到 32包,这都在预期的范围内,但如果来了序号为 33 的包,就超出预期的误差范围了。这时可以通过调整掩码和数组元素的个数大小来适应不同的网络延时。

#17


我也觉得可以用TCP

用IOCP的话
只需要保证缓存在postrecv的时候的顺序 与 将缓存放入接收队列的顺序一致即可

#18


16 楼方案非常不错,谢谢,正在研究



#19


用UDP,只能通过IP地址和端口区别不同的客户端.TCP的话,用socket句柄就行。参考一下这里的socket程序吧,有服务器,也有客户端:
http://download.csdn.net/detail/geoff08zhang/4571358

#1


来个大虾 UP 一下呀

#2


参考RTP协议

#3


楼主说的大量用户有多大,几万个?可以考虑每个用户一个线程分别处理,单个用户根据数据id拼凑

#4


引用 3 楼 xumaojun 的回复:
楼主说的大量用户有多大,几万个?可以考虑每个用户一个线程分别处理,单个用户根据数据id拼凑

一个用户一个线程在这种几万个用户的情况下不行吧,可以考虑开个线程池,LZ这种需求用std::vector完全没问题,单单存储数据的话,自动增长完全满足你的要求

#5


谢谢2楼,我仔细看看 RTP协议 协议

3楼的方案肯定不行,每个用户一个线程。。。再好的服务器也扛不住


谢谢4楼,我研究研究

#6


关于 我这个问题,有个比较重要的地方, 就是我收到的每个包都不是独立的, 是需要把同一系列的 拼接到一起 才可以解析 存储

同一客户端传一次可能会传N 个包,这N个包需要 拼接到一起才有用

所以现在就出现这个问题,如何 分别拼接,存储

#7


就算是千兆的网,你这么大的数据量也会丢包的把?
几万个连接,还敢用udp协议。。。

#8


还是换成tcp的把
用不同的标志头

#9


引用 7 楼 nice_cxf 的回复:
就算是千兆的网,你这么大的数据量也会丢包的把?
几万个连接,还敢用udp协议。。。



对于我丢包这个,我每个包都有 确认机制,  收到包后会给 客户端回传收到的 标志, 客户端一系列包发送完后,会检查哪些没有收到确认,然后重发

#10


每个包定义一个包序列号,服务端接收到所有包后再根据序列号排序,好像那些p2p软件是这样处理的

#11


参考protobuf

#12


引用 11 楼 zhao4zhong1 的回复:
参考protobuf


protobuf ?  详解?

#13


额,还没找到好方法。。。。。主要是 不知道 如何去高效率存储

#14


UDP协议就是一个无序的
可参考UDT

#15


接收其实不是问题,问题 是收到后,如何 分别拼接多用户 发过来的 数据包~

#16


1. UDP 的数据包通过 recvfrom 能得到对端的 IP 和 端口 (sockaddr 类型),基于这个类型的数据结构封装一个类,实现 ‘== ’ 操作,可以用 ACE_INet_Addr
2. 为每个通信对端建立一个控制快,用于缓冲接受的数据,比如:
   struct CLIENT_CB
   {
       uint32_t recv_mask;
       NMVS_PACKHEAD_NEW_T *data[MAX_RECV_MSG];
       int fd;
   }
   'recv_mask' 记录的是数组的哪一个元素上已经存储了了接收的数据,它的数据类型由 MAX_RECV_MSG 而定。如果你只想为每个用户缓冲32个数据包就用 uint32_t,以此类推。
   'fd' 是为了将接收数据转存而打开的文件 (可选)

3. 建立一个关联数据容器,(比如 hash_map<ACE_INet_Addr, CLIENT_CB>). 这样一来,都应发送端的数据就能对应地记录在上述的数据结构当中,每次记录后检查掩码位,如果接收连续的 N 个数据包,可以考虑将其转存到磁盘上,为后续接收腾出内存空间,这时需要进行文件 I/O, 更改掩码值并对数组的元素进行移位操作,由于数组的元素有个数上限,所以这个开销是可以控制的。

4. 这个方案有效性前提是,因为网络延迟导致 UDP 包接收的无序范围是在可接受的范围内。在选择 32 位掩码的时候,假设你在等待前10个包到来的时候来了序号为 11 到 32包,这都在预期的范围内,但如果来了序号为 33 的包,就超出预期的误差范围了。这时可以通过调整掩码和数组元素的个数大小来适应不同的网络延时。

#17


我也觉得可以用TCP

用IOCP的话
只需要保证缓存在postrecv的时候的顺序 与 将缓存放入接收队列的顺序一致即可

#18


16 楼方案非常不错,谢谢,正在研究



#19


用UDP,只能通过IP地址和端口区别不同的客户端.TCP的话,用socket句柄就行。参考一下这里的socket程序吧,有服务器,也有客户端:
http://download.csdn.net/detail/geoff08zhang/4571358

#20