3

我有 2 台机器运行我为测试目的编写的简单 C TCP 服务器,1 台使用 Fedora 16,另一台使用 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()在一个地方而不是两个地方调用。您当前的实现是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 回答