recv()不会阻止

时间:2012-07-30 23:49:03

标签: c ubuntu recv

我有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;
}

1 个答案:

答案 0 :(得分: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;
}