3

テスト目的で作成した単純な C TCP サーバーを実行しているマシンが 2 台あります。1 台は Fedora 16 で、もう 1 台は Ubuntu 11.10 です。私の Fedora マシンは完全に動作しますが、Ubuntu マシンでは recv() がブロックされません。これらのマシンはまったく同じコードを実行していることに注意してください。誰もこれを見たことがありますか?ありがとう

int TcpSocket::ReadFromClient(int socket, char* buf, int len)
{
    char *request = buf;
    int slen = len;

    int c = recv(socket, request, slen, 0);
    while((c > 0) && (request[c-1] != '\n'))
    {
        request += c;
        slen -= c;
        c = recv(socket, request, slen, 0);
    }

    if (c < 0)
    {
        return c;
    }
    else if(c == 0)
    {
        //Sending back an empty string
        buf[0] = '\0';
    }

    return len-slen;
}
4

1 に答える 1

2

コードの意図は、'\n'バイトが到着したときに読み取りを停止することです。その場合、受信したすべてのバイトをチェックするのではなく、バッファの最後のバイトのみをチェックするため、使用可能なバッファ サイズ全体を使用するのではなく、一度に 1 バイトずつソケットから読み取る必要があります。

recv()また、2 か所ではなく 1 か所でのみ呼び出すようにループ ロジックを変更する必要があります。slen=0現在の実装では、バッファーが使い果たされたときにrecv() を呼び出しています。これc=0により、バッファーの最初のバイトが設定され、無効になります。

代わりにこれを試してください:

int TcpSocket::ReadFromClient(int socket, char* buf, int len)
{ 
    int slen = len;
    char ch;

    while (len > 0)
    {
        int ret = recv(socket, &ch, 1, 0); 
        if (ret > 0)
        {
            *buf = ch; 
            ++buf; 
            --len; 

            if (ch == '\n')
                break;
        }
        else
        {
            if ((ret == 0) || (errno != EAGAIN))
                return ret;

            fd_set readfd;
            FD_ZERO(&readfd);
            FD_SET(socket, &readfd);

            timeval tv;
            tv.tv_sec = 5;
            tv.tv_usec = 0;

            ret = select(socket+1, &readfd, NULL, NULL, &tv);
            if (ret < 0)
                return ret;

            if (ret == 0)
            {
                // timeout elapsed while waiting for data
                // do something if desired...
            }
        } 
    } 

    return slen - len;
}
于 2012-07-31T01:23:49.880 に答える