C ++ /赢。没有获得FD_CLOSE

时间:2012-05-08 18:15:54

标签: windows winapi sockets

我有一个异步套接字并调用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
    }
}

3 个答案:

答案 0 :(得分:2)

如果FD_CLOSE失败,您将不会收到connect()通知。您必须订阅FD_CONNECT才能检测到。这在connect() documentation

中明确说明
  

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

     

•使用选择功能确定完成   通过检查套接字是否可写来连接请求。

     

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

     

•如果应用程序使用WSAEventSelect表示对此感兴趣   连接事件,然后将发信号通知相关的事件对象   表示连接操作已完成(成功或   不是)。

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

答案 1 :(得分:1)

如果您致电connect()并获得阻止通知,则必须通过here所述的三种方法之一编写更多代码来监控connect()完成(成功或失败)。< / p>

  

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

     

•使用select功能确定连接完成   请求通过检查套接字是否可写。

     

•如果   应用程序正在使用WSAAsyncSelect来表示对连接的兴趣   事件,然后应用程序将收到FD_CONNECT通知   表示连接操作已完成(成功或   不)。

     

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

答案 2 :(得分:0)

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

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