1

我有一个异步套接字并调用 connect() + GetLastError(),它按预期返回 WSA_WOULD_BLOCK。所以我开始“接收/阅读”线程并将事件订阅到 FD_READ 和 FD_CLOSE。

故事是:连接将依次失败,因为服务器没有启动并运行。我的理解是我的接收线程应该很快得到 FD_CLOSE,我需要跟进清理。

它不会发生。我应该多久收到 FD_CLOSE?这是正确的方法吗?有没有其他方法可以理解 connect() 失败?如果未连接套接字,我应该收到 FD_CLOSE 吗?

在成功调用 DoConnect() 后,我确实开始接收线程并订阅事件,我担心赛车条件会阻止我获得 FD_CLOSE。

这是一些代码:

int RecvSocketThread::WaitForData()
{
     int retVal = 0
     while (!retVal)
     {
         // sockets to pool can be added on other threads.
         // please validate that all of them in the pool are connected
         // before doing any reading on them
         retVal = DoWaitForData();
     }
}

int RecvSocketThread::DoWaitForData()
{
    // before waiting for incoming data, check if all sockets are connected
    WaitForPendingConnection_DoForAllSocketsInThePool();


    // other routine to read (FD_READ) or react to FD_CLOSE
    // create array of event (each per socket) and wait
}
void RecvSocketThread::WaitForPendingConnection_DoForAllSocketsInThePool()
{
    // create array and set it for events associated with pending connect sockets
    HANDLE* EventArray = NULL;
    int counter = 0;
    EventArray = new HANDLE[m_RecvSocketInfoPool.size()];

    // add those event whose associated socket is still not connected
    // and wait for FD_WRITE and FD_CLOSE. At the end of this function
    // don't forget to switch them to FD_READ and FD_CLOSE
    while (it != m_RecvSocketInfoPool.end())
    {
         RecvSocketInfo* recvSocketInfo = it->second;
         if (!IsEventSet(recvSocketInfo->m_Connected, &retVal2))
         {
             ::WSAEventSelect(recvSocketInfo->m_WorkerSocket, recvSocketInfo->m_Event, FD_WRITE | FD_CLOSE);
             EventArray[counter++] = recvSocketInfo->m_Event;
         }
         ++it;
    }
    if (counter)
    {
        DWORD indexSignaled = WaitForMultipleObjects(counter, EventArray, WaitAtLeastOneEvent, INFINITE);

        // no matter what is further Wait doen't return for failed to connect socket

        if (WAIT_OBJECT_0 <= indexSignaled &&
                   indexSignaled < (WAIT_OBJECT_0 + counter))
        {
            it = m_RecvSocketInfoPool.begin();
            while (it != m_RecvSocketInfoPool.end())
            {
                RecvSocketInfo* recvSocketInfo = it->second;
                if (IsEventSet(recvSocketInfo->m_Event, NULL))
                {
                  rc = WSAEnumNetworkEvents(recvSocketInfo->m_WorkerSocket,
                  recvSocketInfo->m_Event, &networkEvents);

                   // Check recvSocketInfo->m_Event using WSAEnumnetworkevents
                   // for FD_CLOSE using FD_CLOSE_BIT
                   if ((networkEvents.lNetworkEvents & FD_CLOSE))
                   {
                       recvSocketInfo->m_FD_CLOSE_Recieved = 1;
                       *retVal = networkEvents.iErrorCode[FD_CLOSE_BIT];
                   }
                   if ((networkEvents.lNetworkEvents & FD_WRITE))
                   {
                       WSASetEvent(recvSocketInfo->m_Connected);
                       *retVal = networkEvents.iErrorCode[FD_WRITE_BIT];
                   }
                }
                ++it;
            }
        }

        // if error - DoClean, if FD_WRITE (socket is writable) check if m_Connected
        // before do any sending
    }
}
4

3 回答 3

2

如果失败,您将不会收到FD_CLOSE通知。connect()您必须订阅才能FD_CONNECT检测到这一点。这在connect() 文档中有明确说明:

使用非阻塞套接字,连接尝试不能立即完成。在这种情况下,connect 将返回 SOCKET_ERROR,而 WSAGetLastError 将返回 WSAEWOULDBLOCK。在这种情况下,有三种可能的情况:

• 使用select 函数通过检查套接字是否可写来确定连接请求的完成。

• 如果应用程序正在使用 WSAAsyncSelect 来表示对连接事件感兴趣,那么应用程序将收到一个 FD_CONNECT 通知,指示连接操作已完成(成功与否)。

• 如果应用程序正在使用 WSAEventSelect 来指示对连接事件的兴趣,则将向关联的事件对象发出信号,指示连接操作已完成(成功与否)。

当 is 时,结果代码connect()将在事件的HIWORD(lParam)LOWORD(lParam)FD_CONNECT。如果结果代码为 0,connect()则表示成功,否则将是 WinSock 错误代码。

于 2012-05-08T20:54:44.063 回答
1

如果您调用connect()并收到阻塞通知,则必须编写更多代码以通过此处connect()描述的三种方法之一来监视完成(成功或失败)。

使用非阻塞套接字,连接尝试不能立即完成。在这种情况下,connect 将返回 SOCKET_ERROR,而 WSAGetLastError 将返回 WSAEWOULDBLOCK。在这种情况下,有三种可能的情况:

• 使用select 函数通过检查套接字是否可写来确定连接请求的完成。

• 如果应用程序正在使用 WSAAsyncSelect 来表示对连接事件感兴趣,那么应用程序将收到一个 FD_CONNECT 通知,指示连接操作已完成(成功与否)。

• 如果应用程序正在使用 WSAEventSelect 来指示对连接事件的兴趣,那么将向关联的事件对象发出信号,指示连接操作已完成(成功与否)。

于 2012-05-08T19:12:57.227 回答
0

我想我需要在创建套接字句柄后开始接收线程,但在调用 connect 之前。在异步套接字上调用 connect 后创建它为时已晚。对于同步套接字,这两个调用 createsocket() 和 connect() 只是两个连续的行。不适用于非阻塞。

在这种情况下,在接收线程开始时,我需要检查 FD_CONNECT 和/或 FD_WRITE 以便了解连接尝试状态。

于 2012-05-09T13:51:19.493 回答