8

私のプログラムでは、サーバーに到達できない場合、接続機能に時間がかかりすぎます。だから私はselect()を使って接続するためにタイムアウトを与えようとします。問題は、recvfrom()を使用してサーバーからデータを受信しようとすると、エラー「EAGAIN」が発生することです。これは、サーバーに接続してデータを受信するために使用されるコードです。

int sock;
struct sockaddr_in addr;
int connectWithServer
{

    int status;

    struct timeval  timeout;
    timeout.tv_sec = 10;
    timeout.tv_usec = 0;

    addr.sin_port = htons(port);
    sock = socket (AF_INET,SOCK_STREAM,0);
    inet_pton(AF_INET,serverIP,&addr.sin_addr);

    fd_set set;
    FD_ZERO(&set);
    FD_SET(sock, &set);

    fcntl(sock, F_SETFL, O_NONBLOCK);

    if ( (status = connect(sock, (struct sockaddr*)&addr, sizeof(addr))) == -1)
    {
        if ( errno != EINPROGRESS )
            return status;

    }
    status = select(sock+1, NULL, &set, NULL, &timeout);

    return status;
}


long int receiveResponse (void *response , unsigned int length)
{
    socklen_t sockLen = sizeof(struct sockaddr);
    long int received = recvfrom(sock, response, length, 0,(struct sockaddr *)&addr,  &sockLen);
    printf("Received %ld bytes...  err %d\n",received, errno);

    return received;
}
4

4 に答える 4

6

Connect()関数のタイムアウトの設定Cでのtcpソケットプログラミングが機能しない

修正。接続タイムアウトの設定機能しています。「機能していない」とは、後続の「」です。これrecvfrom()は、ソケットを非ブロッキングモードのままにして、結果の処理をどうするかわからないためです。EAGAIN.したがって、を使用select()して、ソケットがいつ読み取る準備ができているか、接続が完了した後、ソケットをブロッキングモードに戻します。

于 2013-01-10T22:21:13.193 に答える
5

EAGAINソケットバッファから読み取るデータがなく、ソケットが。として設定されているために受信しますnonblocking。あなたはピアに接続していないので、私はそれに驚いていません。

これを見てくださいman recvfrom

ソケットで使用可能なメッセージがない場合、ソケットが非ブロッキングでない限り、受信呼び出しはメッセージの到着を待機します(fcntl(2)を参照)。この場合、値-1が返され、外部変数errnoがEAGAINに設定されます。受信呼び出しは通常、要求された全額の受信を待つのではなく、要求された量までの利用可能なデータを返します。

別のケースは次のようになります。

  • ソケットが接続されている可能性がありますが、何かが受信されたかどうかを確認するのが速すぎます。これを回避するには、recvfromの前に別のselectを配置して、何かを受信したことが確実な場合にのみ、ソケットバッファからパケットを抽出します(呼び出しreadfromまたは単に)。read
于 2013-01-10T09:18:08.800 に答える
5

最初に成功した選択は、接続操作が完了したことを意味しますが、必ずしも成功したことを意味するわけではありません。接続のマニュアルページから、SO_ERROR正常に完了したことを確認する必要があります。

書き込み用のソケットを選択することにより、完了のために(2)またはpoll(2)を選択することができます。 select(2)が書き込み可能性を示したら、getsockopt(2)を使用してレベルSOL_SOCKETのSO_ERRORオプションを読み取り、connect()が正常に完了したか(SO_ERRORがゼロ)または失敗したか(SO_ERRORはここにリストされている通常のエラーコードの1つであり、失敗の理由)。

したがって、コードでは次のようにする必要があります。

int ret;
ret=select(sockfd+1, NULL, &wfds, NULL, NULL); //should use timeout
if(ret==1 && getSocketOpt(sockfd, SO_ERROR) ==0) {
    return 0; //successfully connected
}

次に、他の回答で述べたように、ソケットからの書き込みまたは読み取りの前に、もう一度selectを呼び出す必要があります。

于 2013-01-10T10:11:31.887 に答える
5

recv()を呼び出す前に、ソケットを再度ブロッキングモードに設定する必要があります。

fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) & ~O_NONBLOCK);
于 2013-08-19T05:45:45.513 に答える