0

select を使用して、ネットワーク上の別のホストからの確認応答を待ちますが、常に 0 を返します。同様の質問を持つ他のスレッドを見たことがありますが、それらの問題は常に、fd_set をリセットしていないか、またはselect() の最初のパラメーターに正しい値を渡していません。fd_setをリセットしているため、それが問題の原因であるとは考えられず、msdnによると、明らかに最初のパラメーターがWindowsで無視されます。

while(!done)
{
    //send acknowledgment and sequence number
    sendto(_clientSocket, buff, 2, 0, (LPSOCKADDR)&_sockAddr, sizeof(SOCKADDR));

    //wait for acknowledgment
    struct timeval timeout;
    timeout.tv_sec = _rttInfo.timeout/1000;
    timeout.tv_usec = _rttInfo.timeout * 1000;

    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(_clientSocket, &fds);

    //wait for client to send an acknowledgement
    //wait for the socket to be ready for reading
    int res = select(0, &fds, NULL, NULL, &timeout);
    int err = WSAGetLastError();

    if(res == 0) //if timed out, retry
    {
        timedOutCount++;
        if(timedOutCount >= MAX_TIMEOUTS)
        {
            cout << "Handshaking complete _" << endl;
            return true;
        }
        else
        {
            cout << "Acknowledgement timed out, resending sequence number and acknowledgement" << endl;
            continue;
        }
    }

//下にelse ifステートメントがありますが、そこには行きません

何があっても、この時点では 0 が返されます。クライアントとサーバーがソケットを介して互いに情報を送信しているのを見たので、クライアント側で間違ったアドレスに送信しているとは思いません。select() が待機しているパケットを送信するためのクライアント側のコードは次のとおりです。

buff[0] = _seqNum;
res = sendto(_socket, buff, 2, 0, (LPSOCKADDR) &sa_in, sizeof(SOCKADDR));

この問題を経験したのは私だけではありません。これに対処する方法を知っている人はいますか?

編集: 誰かが _sockAddr が入力されている場所を尋ねたので、ここに含めます: ClientThread クラスがインスタンス化されている場所があり、sockaddr_in が渡されていることがわかります。

while(true)
{
    try
    {
        // Wait for connection
        cout << "Waiting for incoming connection... ";

        sockaddr_in clientSockAddr;
        //  int clientSockSize = sizeof(clientSockAddr);

        // Listen in on the bound socket:
        //  hClientSocket = accept(hSocket,
        //  reinterpret_cast<sockaddr*>(&clientSockAddr),
        //  &clientSockSize);
        unsigned char seqNum = 0; 

        int addrSize = sizeof(clientSockAddr);
        //wait for a connection
        int res=0;

        //loop until we get a packet that's from someone new
        bool blocking = true;

        while(blocking)
        {
            res = recvfrom(hSocket, buff, strlen(buff), 0, (LPSOCKADDR)&clientSockAddr, &addrSize);         
            bool foundMatch = false;
            //check if we're already handling this client. If so, keep blocking. Otherwise, break out of the loop
            for(list<ClientThread*>::iterator it = clientList.begin(); it != clientList.end(); it++)
            {
                //compare network addresses
                if((*it)->GetSockAddr().sin_addr.S_un.S_addr == clientSockAddr.sin_addr.S_un.S_addr)
                {
                    foundMatch = true; 
                    break;
                }
            }
            if(!foundMatch)
            {
                blocking = false;
            }
        }
        err =  WSAGetLastError();  


        // Check if we can create a new client thread
        if(res != SOCKET_ERROR && res != 0)
        {
            seqNum = (unsigned char) buff[0]; //get the sequence number for handshaking
            cout << "accepted connection from: " << GetHostDescription(clientSockAddr) << endl;
            //start a client thread, to handle requests from this client.
            ClientThread* pThread = new ClientThread(hSocket, clientSockAddr, this, seqNum);
            clientList.push_back(pThread);
            pThread->start(); 
        }
    //  if (hClientSocket==INVALID_SOCKET)
    //      throw "accept function failed.";
    }
    catch(char* ex)
    {
        cerr << "\nError: " << ex << endl;
        bSuccess = false; 
    }

}

Edit2: さらにデバッグすると、select ではなく recvfrom の呼び出しでメッセージが受信されるため、sendto の呼び出しが目的のターゲットに到達していることがわかりました。ただし、非ブロッキング呼び出しを使用できるようにする必要があります。

4

3 に答える 3

3

sendto()失敗する可能性がありますが、エラーをチェックしていません。 sizeof(SOCKADDR)最後のパラメーターで使用するのは間違っています。sizeof(_sockAddr)代わりに使用してください:

if (sendto(_clientSocket, buff, 2, 0, (LPSOCKADDR)&_sockAddr, sizeof(_sockAddr)) == SOCKET_ERROR)
{
    cout << "Handshaking failed, error " << WSAGetLastError() << endl;
    return false;
}

_sockAddr変数が有効なsockaddr_insockaddr_in6、またはsockaddr_storageないことを確認してくださいsockaddr

別の注意として、_rttInfo.timeoutがミリ秒単位で表現されていると仮定すると、timeout.tv_usec値が間違って計算されています。代わりに、次のようにする必要があります。

struct timeval timeout;
timeout.tv_sec = _rttInfo.timeout / 1000;
timeout.tv_usec = (_rttInfo.timeout % 1000) * 1000;
于 2012-11-12T23:00:00.843 に答える
1

予想通り、(rttInfo に含まれる値に基づいて) タイムアウトを要求するので、タイムアウトを選択します。もっと長く待ちたい場合は rttInfo を調整するか、何かが起こるまで待ちたい場合はタイムアウトに null 値を指定します。

于 2012-11-12T22:45:07.077 に答える
0

タイムアウトを設定したため、タイムアウトを選択します。ブロック操作が必要な場合は、タイムアウトを null にする必要があります: http://msdn.microsoft.com/en-us/library/windows/desktop/ms740141(v=vs.85).aspx

あなたが言ったように、最初のパラメータは無視されているようです。行上の何か:

int res = select(0, &fds, NULL, NULL, NULL);
于 2012-11-12T22:41:49.877 に答える