You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:13:28