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()サブスクライブする必要があります。これは、 connect() のドキュメントFD_CONNECTに明確に記載されています。

ノンブロッキング ソケットでは、接続の試行をすぐに完了できません。この場合、connect は SOCKET_ERROR を返し、WSAGetLastError は WSAEWOULDBLOCK を返します。この場合、次の 3 つのシナリオが考えられます。

• select 関数を使用して、ソケットが書き込み可能かどうかを確認することにより、接続要求の完了を判断します。

アプリケーションが接続イベントへの関心を示すために WSAAsyncSelect を使用している場合、アプリケーションは接続操作が完了したこと (成功または失敗) を示す FD_CONNECT 通知を受け取ります。

アプリケーションが接続イベントへの関心を示すために WSAEventSelect を使用している場合、接続操作が完了したこと (成功または失敗) を示す信号が関連付けられたイベント オブジェクトに送信されます。

の結果コードはconnect()、 の場合にイベントのHIWORD(lParam)値になりLOWORD(lParam)ますFD_CONNECT。結果コードが 0 の場合connect()は成功、それ以外の場合は WinSock エラー コードになります。

于 2012-05-08T20:54:44.063 に答える
1

呼び出しconnect()てブロッキング通知を受け取った場合は、ここでconnect()説明する3つの方法のいずれかを使用して、完了(成功または失敗)を監視するためのコードをさらに作成する必要があります。

ノンブロッキングソケットでは、接続の試行をすぐに完了できません。この場合、connectはSOCKET_ERRORを返し、WSAGetLastErrorはWSAEWOULDBLOCKを返します。この場合、次の3つのシナリオが考えられます。

•select関数を使用して、ソケットが書き込み可能かどうかを確認することにより、接続要求の完了を判別します。

•アプリケーションがWSAAsyncSelectを使用して接続イベントへの関心を示している場合、アプリケーションは、接続操作が(成功したかどうかにかかわらず)完了したことを示すFD_CONNECT通知を受け取ります。

•アプリケーションがWSAEventSelectを使用して接続イベントへの関心を示している場合、関連するイベントオブジェクトは、接続操作が(成功したかどうかにかかわらず)完了したことを示すシグナルが送信されます。

于 2012-05-08T19:12:57.227 に答える
0

ソケットハンドルが作成されたら、接続が呼び出される前に、スレッドの受信を開始する必要があると思います。非同期ソケットでconnectが呼び出された後、作成するには遅すぎます。同期ソケットの場合、これらの2つの呼び出しcreatesocket()とconnect()は、2つの連続した行でした。非ブロッキングでは機能しません。

この場合、スレッドの受信開始時に、接続試行ステータスを通知するために、FD_CONNECTまたはFD_WRITE、あるいはその両方をチェックする必要があります。

于 2012-05-09T13:51:19.493 に答える