Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Winsock WSAEventSelect()使套接字描述符不再是套接字_Winsock - Fatal编程技术网

Winsock WSAEventSelect()使套接字描述符不再是套接字

Winsock WSAEventSelect()使套接字描述符不再是套接字,winsock,Winsock,我正在编写一个跨平台套接字处理库(它还以一种协议无关的方式处理串行协议和一大堆其他协议。-我不是在重新发明轮子) 我需要模拟Linux轮询函数。我开始使用的代码使用select并运行良好,但无法从另一个线程中断它,因此我被迫开始使用事件对象。我最初的尝试是: WSACreateEvent() WSAEventSelect() to associate the socket with the event object. WaitForMultipleObjectsEx() to wait on a

我正在编写一个跨平台套接字处理库(它还以一种协议无关的方式处理串行协议和一大堆其他协议。-我不是在重新发明轮子)

我需要模拟Linux轮询函数。我开始使用的代码使用select并运行良好,但无法从另一个线程中断它,因此我被迫开始使用事件对象。我最初的尝试是:

WSACreateEvent()
WSAEventSelect() to associate the socket with the event object.
WaitForMultipleObjectsEx() to wait on all sockets plus my interrupt event object.
select() to work out what events actually occurred on the socket.
accept()/send()/recv() to process the sockets (later and elsewhere).
这失败了
accept()
声称文件描述符不是套接字。如果我注释掉了对
WSAEventSelect()
的调用,本质上恢复到我以前的代码,那么一切都可以正常工作(除了我不能中断)

然后我意识到我做错了什么(根据微软的独裁统治)。我应该使用
WSAEnumNetworkEvents()
,而不是使用
select()
来计算每个套接字上发生了什么事件。因此,我重新编写了代码,以正确的方式执行此操作,记住在之后调用
WSAEventSelect()
以解除事件对象与文件描述符的关联,这样(祈祷)
accept()
现在就可以工作了

现在
WSAEnumNetworkEvents()
返回一个错误,并且
WSAGetLastError()
告诉我错误是
WSAENOTSOCK

这是一个插座。我按照MSDN告诉我应该做的方式做事(考虑到文档的总体质量差)。但是,
WSAEventSelect()
似乎导致将文件描述符标记为文件而不是套接字

我现在非常讨厌微软

以下是我的代码的精简版本:

bool do_poll(std::vector<struct pollfd> &poll_data, int timeout)
{
    ...
    for (const auto &fd_data : poll_data) {
        event_mask = 0;
        if (0 != (fd_data.events & POLLIN)) {
            // select() will mark a socket as readable when it closes (read size = 0) or (for
            // a listen socket) when there is an incoming connection. This is the *nix paradigm.
            // WSAEventSelect() hasseparate events.
            event_mask |= FD_READ;
            event_mask |= FD_ACCEPT;
            event_mask |= FD_CLOSE;
        }
        if (0 != (fd_data.events & POLLOUT)) {
            event_mask |= FD_WRITE;
        }
        event_obj = WSACreateEvent();
        events.push_back(event_obj);
        if (WSA_INVALID_EVENT != event_obj) {
            (void)WSAEventSelect((SOCKET)fd_data.fd, event_obj, event_mask);
        }
    }

    lock.lock();

    if (WSA_INVALID_EVENT == interrupt_obj) {
        interrupt_obj = WSACreateEvent();
    }

    if (WSA_INVALID_EVENT != interrupt_obj) {
        events.push_back(interrupt_obj);
    }

    lock.unlock();

    ...

    (void)WaitForMultipleObjectsEx(events.size(), &(events[0]), FALSE, dw_timeout, TRUE);

    for (i = 0u; i < poll_data.size(); i++) {
        if (WSA_INVALID_EVENT == events[i]) {
            poll_data[i].revents |= POLLERR;
        } else {
            if (0 != WSAEnumNetworkEvents((SOCKET)(poll_data[i].fd), events[i], &revents)) {
                poll_data[i].revents |= POLLERR;
            } else {
                if (0u != (revents.lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))) {
                    poll_data[i].revents |= POLLIN;
                }

                if (0u != (revents.lNetworkEvents & FD_WRITE)) {
                    poll_data[i].revents |= POLLOUT;
                }
            }

            (void)WSAEventSelect((SOCKET)(poll_data[i].fd), NULL, 0);
            (void)WSACloseEvent(event_obj);
        }
    }

    ...
}
booldo_轮询(std::vector&poll_数据,int超时)
{
...
用于(常量自动和fd_数据:轮询_数据){
事件屏蔽=0;
如果(0!=(fd_data.events和POLLIN)){
//select()将在套接字关闭时(读取大小=0)或(对于)将其标记为可读
//一个监听套接字),当有一个传入连接时。这是*nix范例。
//WSAEventSelect()已分离事件。
事件|掩码|=FD|读;
事件|掩码|=FD|U接受;
事件|掩码|=FD |关闭;
}
如果(0!=(fd_data.events&POLLOUT)){
事件|掩码|=FD|U写入;
}
event_obj=WSACreateEvent();
事件。推回(事件对象);
if(WSA\U无效\U事件!=事件\U obj){
(void)WSAEventSelect((套接字)fd_data.fd、event_obj、event_mask);
}
}
lock.lock();
如果(WSA\U无效\U事件==中断\U obj){
中断_obj=WSACreateEvent();
}
if(WSA\U无效\U事件!=中断\U obj){
事件。推回(中断对象);
}
lock.unlock();
...
(void)WaitForMultipleObjectsEx(events.size(),&(events[0]),FALSE,dw_timeout,TRUE);
对于(i=0u;i
调用
WSAEventSelect((SOCKET)fd,NULL,0)
在我从works开始的代码中调用
select()
之后!万岁!但是,由于
wsaemnetorkevents()
需要事件对象,并且可能需要它仍然与套接字关联,这并不能解决我的问题。从MSDN文档中可以看出,您应该在套接字的生存期内关联事件对象,并且调用
WSAEventSelect()
同一个套接字的第二次清除内部网络事件日志。(`基本上已损坏。我的“解决方案”是使用我的第一个选项,但在调用
select()
之后,使用空指针调用
WSAEventSelect()
。这是一堆热气腾腾的微软产品,但它确实有效。我不知道为什么
select()
不调用
WSAEventSelect()
,而
accept()
和朋友却不行。我想知道为什么。我还对使用
wsaemnetworkevents()
的工作示例感兴趣。我不敢相信,即使是微软的无能者也会发布一个在所有情况下都完全无法工作的API。也许是完全不正确的文档让我感到困惑。这可能会有帮助: