能否将WaitForMultipleObjects()与ACE_SOCK_Stream配合实现仅在有数据时返回?
能不能用WaitForMultipleObjects()配合ACE_SOCK_Stream实现数据可读时返回?
当然可以,但你的代码里有个核心问题导致它直接返回——Windows下的原生socket句柄不能直接被WaitForMultipleObjects()等待,ACE_SOCK_Stream的get_handle()返回的就是原生socket句柄,直接传进去的话,函数不会识别它的IO状态,自然会立即返回。
问题根源
WaitForMultipleObjects()等待的是「同步对象」(比如事件、互斥量、信号量),而原生socket句柄不属于这类对象。要让socket的可读事件能被它等待,你需要先把socket和一个WSA事件对象绑定,通过事件来监听socket的FD_READ事件。
修正后的实现步骤
这里给你调整后的代码,加上必要的绑定和事件处理:
#include <winsock2.h> #include <ACE/ACE_SOCK_Stream.h> #include <iostream> int main() { // 假设你已经初始化了ACE和Winsock,并且sock_stream已经连接成功 ACE_SOCK_Stream sock_stream; // 1. 创建一个WSA事件对象,用于监听socket事件 HANDLE sockEvent = WSACreateEvent(); if (sockEvent == WSA_INVALID_EVENT) { std::cerr << "WSACreateEvent failed: " << WSAGetLastError() << std::endl; return 1; } // 2. 将socket和事件绑定,监听FD_READ(数据可读)事件 int ret = WSAEventSelect(sock_stream.get_handle(), sockEvent, FD_READ); if (ret == SOCKET_ERROR) { std::cerr << "WSAEventSelect failed: " << WSAGetLastError() << std::endl; WSACloseEvent(sockEvent); return 1; } DWORD timeoutMs = 5 * 1000; HANDLE handles[] = {sockEvent}; DWORD handlesCount = _countof(handles); while (true) { DWORD waitResult = WaitForMultipleObjects(handlesCount, handles, FALSE, timeoutMs); switch (waitResult) { case WAIT_OBJECT_0: { // 事件触发,处理socket可读事件 WSANETWORKEVENTS networkEvents; ret = WSAEnumNetworkEvents(sock_stream.get_handle(), sockEvent, &networkEvents); if (ret == SOCKET_ERROR) { std::cerr << "WSAEnumNetworkEvents failed: " << WSAGetLastError() << std::endl; break; } // 检查是否是FD_READ事件触发 if (networkEvents.lNetworkEvents & FD_READ) { if (networkEvents.iErrorCode[FD_READ_BIT] == 0) { std::cout << "Socket has data to read!" << std::endl; // 这里可以调用sock_stream.recv()读取数据 char buf[1024]; ssize_t bytesRead = sock_stream.recv(buf, sizeof(buf)); if (bytesRead > 0) { std::cout << "Read " << bytesRead << " bytes: " << std::string(buf, bytesRead) << std::endl; } } else { std::cerr << "FD_READ error: " << networkEvents.iErrorCode[FD_READ_BIT] << std::endl; } } break; } case WAIT_TIMEOUT: std::cout << "Wait timed out after " << timeoutMs << "ms" << std::endl; break; default: std::cerr << "WaitForMultipleObjects failed: " << GetLastError() << std::endl; goto cleanup; } } cleanup: WSACloseEvent(sockEvent); return 0; }
额外提示
- 每次事件触发后,一定要调用
WSAEnumNetworkEvents(),否则事件会一直处于触发状态,WaitForMultipleObjects()会立即返回。 - 如果你的代码需要跨平台,其实更推荐使用ACE自带的ACE_Reactor机制,它封装了跨平台的IO复用(比如Windows的IOCP、Linux的epoll),比直接调用Windows API更便携,也更符合ACE的设计理念。
内容的提问来源于stack exchange,提问作者Ronen Ness
相关产品推荐
相关产品推荐

