如何从一个UDP套接字处理多个客户端?

时间:2014-04-09 17:04:58

标签: c++ multithreading sockets udp iocp

我现在处理一个问题,我不知道正确/最佳解决方案。

考虑以下示例:

想象一下你有一个Socket,就像这样:

SOCKET s = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);

在这个套接字上,我将其称为" ServerSocket",来自许多不同的ip + s +端口(客户端)的传入许多udp数据包。

因为在这个套接字上的recvfrom()中创建多个线程阻塞似乎不是一个好主意,所以我想到了(可能)一个专用线程,只是在recvfrom()上阻塞放置那些ip + port + msg组合成某种"全局队列" (std :: queue,由互斥锁保护)。

到目前为止,这么好。

我了解IOCP,关于它的第一个问题是:在一个插槽上使用IOCP来解决这类问题是否有意义?我遇到的问题是,即使UDP数据包(我们都知道协议本身无法保证)以正确的顺序进入套接字,也会出现线程排序的问题。 例如,如果我使用具有四个线程的IOCP和四个未完成的重叠wsarecvfrom(),则包1 2 3 4可以由线程调整器重新排序,例如,到3 4 1 2。 如果只使用一个未完成的wsarecvfrom(),一切都按预期工作,因为一次只有一个线程处理wsarecvfrom(),将该消息放入客户端队列并发布下一个重叠的wsarecvfrom()。

此外,我想在阻止模式下模拟recvmsg()和sendmsg()等函数,但问题是,例如,如果您有数千个客户端,则无法打开1000个线程,这些线程都具有专用的recvmsg()阻塞功能。客户端消息队列的条件变量。 这也是一个问题,因为客户端可能会被删除,因为它可能包含类似" CLOSE_CONNECTION"之类的东西来模拟closesocket(),就像TCP使用它一样。

我需要使用UDP,因为用户发送的数据对时间至关重要,但它并不一定要可靠;只有状态消息应该尽可能可靠,例如, " CONNECT_REQUEST",如果客户"连接" (就像tcp那样,我们都知道,udp不会这样做,所以如果有必要,我们必须自己编写)。 也需要客户端消息的顺序。

总结一下,应该给出以下标准: - 需要客户端消息部分的有序消息 - 客户端消息的可靠性不是必需的(仅适用于状态包,例如" ACK_PACKAGE"等等......我们正在谈论最新消息>重要而不是可靠性收到消息) - 必须管理许多客户端,并且必须检测断线连接(软/硬,如果客户端插入网络电缆或其他东西......)(计时器的线程池?)

所以我的最后一个问题是:达到这样一个目标的最佳方法是什么?使用TCP,它会更容易,因为一个IOCP线程可以监听一个accept()ed TCP套接字,因此不存在该线程重新排序问题。使用一个UDP套接字,你不能这样做,所以也许必须有一些像重叠的请求,但只是一个......好吧,"自我定义"事件

1 个答案:

答案 0 :(得分:2)

您是正确的,因为使用多个线程为IOCP提供服务的基于IOCP的服务器可以并且将需要显式排序,以确保以正确的顺序处理来自多个并发读取的结果。 TCP连接也是如此(参见here)。

我通常用TCP处理这个问题的方法是使用每个连接计数器,这是一个值作为元数据添加到用于该连接上的recv的每个缓冲区。然后,您只需确保按顺序处理缓冲区,因为已发出的读取序列是IOCP中的读取完成序列(它只是从IOCP读取导致问题的多个线程的调度)。

如果您有一个所有对等体发送到的“众所周知的端口”,您不能采用这种方法,因为您的序列号没有与之关联的“连接”。

此外,UDP增加的一个复杂因素是你和你的同伴之间的路由器可能会在他们找到你之前设法重新排序或复制任何数据报。这是不太可能的,但如果你不考虑它,那么当你将它演示给一个重要的人时,这肯定是第一件事......

这导致了对UDP进行排序的事实,您需要在数据报的数据部分内部有一个序列号。然后,您会遇到UDP数据报可能丢失的问题,因此序列号对于确保按顺序处理所有入站数据不太有用,并且仅用于确保您永远不会按顺序处理任何数据报。也就是说,如果你的数据报中有一个序列号,那么你可以确保永远不会处理来自该对等体的数据报,其序列号小于或等于你上次处理的序列号(实际上你需要丢弃)可能有效的数据。)

这实际上与使用单个对等体的单线程系统有同样的问题,但是当你得到一个恰好产生网络配置的重要演示时,你很可能会在没有这么严格的情况下离开重复数据报或无序数据报(两者都非常合法)。

要从系统中获得更高的可靠性,您需要在UDP之上构建更多协议。也许看看this question及其答案。然后小心不要为TCP以外的其他网络用户构建更慢,更不好,更不礼貌的东西......