【发布时间】:2014-05-23 01:17:54
【问题描述】:
我现在正在处理一个我不知道正确/最佳解决方案的问题。
考虑以下示例:
假设你有一个 Socket,像这样:
SOCKET s = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
在这个我将称为“ServerSocket”的套接字上,有许多来自许多不同 ip 和端口(客户端)的 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”的包来模拟 TCP 使用它的 closesocket()。
我需要使用UDP,因为用户发送的数据是时间关键的,但它不一定是可靠的;只有状态消息应该尽可能可靠,例如“CONNECT_REQUEST”,如果客户端“连接”(就像 tcp 会这样做,我们都知道,udp 不会这样做,所以如果需要,我们必须自己编写)。 也需要按顺序接收客户端消息。
总而言之,应给出以下标准: - 需要客户端消息部分的有序消息 - 客户端消息的可靠性不是必需的(仅对于状态包,如“ACK_PACKAGE”等......我们正在谈论最新消息>比接收消息的可靠性更重要) - 必须管理许多客户端,并且必须检测断开连接(软/硬,例如客户端插入网线或其他东西......)之类的事情(定时器线程池?)
所以我的最后一个问题是:实现这样的目标的最佳方法是什么?使用 TCP 会更容易,因为一个 IOCP 线程可以侦听一个接受()处理的 TCP 套接字,因此不会出现线程重新排序问题。使用一个 UDP 套接字,你不能那样做,所以也许必须有类似重叠请求之类的东西,但只是为了一个......好吧,“自定义”事件。
【问题讨论】:
-
你一开始就丢弃的多线程解决方案没有任何问题。这不是唯一的方法,但它是一种非常简单的方法。
-
void thread_one() { recvfrom(serverSocket....); } void thread_two() { recvfrom(serverSocket....); }这样吗?? -
当然可以。每条消息只有一个线程接收,您也可以通过同一个套接字从多个线程发送数据报。 send() 和 recv() 调用是系统调用,因此是原子调用。
标签: c++ multithreading sockets udp iocp