windows 在 WinSock 中处理异步套接字?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5037832/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Handling asynchronous sockets in WinSock?
提问by Jason Dietrich
I'm using a message window and WSAAsyncSelect. How can I keep track of multiple sockets (the clients) with one message window?
我正在使用消息窗口和 WSAAsyncSelect。如何使用一个消息窗口跟踪多个套接字(客户端)?
回答by Chris Becke
Windows Supports several modes of socket operation, and you do need to be clear which one you are using:
Windows 支持多种套接字操作模式,您需要清楚您使用的是哪一种:
- Blocking sockets. send and recv block.
- Non-Blocking sockets: send and recv return E_WOULDBLOCK, and select() is used to determine which sockets are ready
- Asynchronous sockets: WSAAsyncSelect - sockets post event notifications to an HWND.
- EventSockets: WSAEventSelect - sockets signal events.
- Overlapped Sockets: WSASend and WSARecv are used with sockets by passing in the OVERLAPPED structures. Overlapped Sockets can be combined with IOCompletionPorts and provide the best scalability.
- 阻塞套接字。发送和接收块。
- 非阻塞套接字:send 和 recv 返回 E_WOULDBLOCK,select() 用于确定哪些套接字已就绪
- 异步套接字:WSAAsyncSelect - 套接字将事件通知发布到 HWND。
- EventSockets:WSAEventSelect - 套接字信号事件。
- 重叠套接字:WSASend 和 WSARecv 通过传入重叠结构与套接字一起使用。Overlapped Sockets 可以与 IOCompletionPorts 结合使用并提供最佳的可扩展性。
In terms of convenience, asynchronous sockets are simple, and supported by MFC CAsyncSocket class.
就方便而言,异步套接字比较简单,并且由 MFC CAsyncSocket 类支持。
Event Sockets are tricky to use as the maximum number of objects passable to WaitForMultipleObjects is 64.
事件套接字使用起来很棘手,因为可传递给 WaitForMultipleObjects 的最大对象数是 64。
Overlapped sockets, with IO CompletionPorts, is the most scalable way to handle sockets and allows windows based servers to scale to tens of thousands of sockets.
带有 IO CompletionPorts 的重叠套接字是处理套接字的最具可扩展性的方式,并允许基于 Windows 的服务器扩展到数万个套接字。
In my experience, when using Async Sockets, the following things come to mind:
根据我的经验,在使用异步套接字时,会想到以下几点:
Handling FD events via window messages can handle "lots" of sockets, but performance will begin to suffer as all the event handling is done in one thread, serialized through a message queue that might be busy handling UI events too if used in a single threaded GUI app.
If you are hosting GUI windows or timers on the same thread as lots of sockets: WM_TIMER and WM_PAINT messages are low priority, and will only be generated if the message queue is empty. Very busy sockets can thus cause GUI painting, or SetTimer based timing to fail.
Creating a dedicated worker thread to handle your sockets if hosting a GUI solves these problems. Given that the worker thread will have a message loop, you can use the message queue for inter-thread comms - just post WM_APP messages to the thread.
The easiest way to map FD callbacks to your socket objects is to create an Array of SocketObjects for each HWND that will be receiving messages, and then use WM_USER+index as the message ID each time you call WASAsyncSelect. Then, when you receive messages in the range WM_USER to WM_USER+(array size) you can quickly extract the corresponding state object. WM_USER is 0x400, and WM_APP is 0x8000, so you can index up to 31744 sockets per message window using this method.
Don't use a static scope array. You need to associate the array with the window as you might want to create sockets on multiple threads. Each thread will need its own message loop, and message window.
HWND_MESSAGE is your friend
通过窗口消息处理 FD 事件可以处理“大量”套接字,但性能将开始受到影响,因为所有事件处理都在一个线程中完成,通过消息队列进行序列化,如果在单线程中使用,该队列也可能忙于处理 UI 事件图形用户界面应用程序。
如果您在与许多套接字相同的线程上托管 GUI 窗口或计时器:WM_TIMER 和 WM_PAINT 消息是低优先级的,并且只有在消息队列为空时才会生成。因此,非常繁忙的套接字会导致 GUI 绘制或基于 SetTimer 的计时失败。
如果托管 GUI 可以解决这些问题,则创建一个专用的工作线程来处理您的套接字。鉴于工作线程将有一个消息循环,您可以使用消息队列进行线程间通信 - 只需将 WM_APP 消息发布到线程。
将 FD 回调映射到套接字对象的最简单方法是为每个将接收消息的 HWND 创建一个 SocketObjects 数组,然后在每次调用 WASAsyncSelect 时使用 WM_USER+index 作为消息 ID。然后,当您收到 WM_USER 到 WM_USER+(数组大小)范围内的消息时,您可以快速提取相应的状态对象。WM_USER 为 0x400,WM_APP 为 0x8000,因此您可以使用此方法为每个消息窗口索引多达 31744 个套接字。
不要使用静态范围数组。您需要将数组与窗口相关联,因为您可能希望在多个线程上创建套接字。每个线程都需要自己的消息循环和消息窗口。
HWND_MESSAGE 是你的朋友
回答by Remy Lebeau
The wParam
parameter of the window message that you tell WSAAsyncSelect()
to send will specify the socket that triggered the message. This is clearly stated in the WSAAsyncSelect()
documentation:
wParam
您告诉WSAAsyncSelect()
发送的窗口消息的参数将指定触发消息的套接字。这在WSAAsyncSelect()
文档中明确说明:
When one of the nominated network events occurs on the specified socket s, the application window hWnd receives message wMsg. The wParam parameter identifies the socket on which a network event has occurred. The low word of lParam specifies the network event that has occurred. The high word of lParam contains any error code. The error code be any error as defined in Winsock2.h.
当指定的套接字 s 上发生指定的网络事件之一时,应用程序窗口 hWnd 会收到消息 wMsg。wParam 参数标识发生网络事件的套接字。lParam 的低位字指定已发生的网络事件。lParam 的高位字包含任何错误代码。错误代码是 Winsock2.h 中定义的任何错误。