Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/28.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 当recv buf已经有数据时,tcp套接字recv会返回“资源暂时不可用”吗_Linux_Sockets_Unix_Tcp_Recv - Fatal编程技术网

Linux 当recv buf已经有数据时,tcp套接字recv会返回“资源暂时不可用”吗

Linux 当recv buf已经有数据时,tcp套接字recv会返回“资源暂时不可用”吗,linux,sockets,unix,tcp,recv,Linux,Sockets,Unix,Tcp,Recv,我使用epoll实现TCP套接字通信以监视所有客户端事件,在for循环中只有一个线程处理所有客户端。每个插座都是非阻塞的 现在我遇到了一个问题,当客户端发送的数据超过MTU,意味着几个片段数据包时,服务器总是无法完全读取所有数据。 如下图所示,我首先读取头部,从头部获取pdu透镜,然后读取pdu部分 问题是,虽然我成功地读取了头部,紧跟着pdu recv,但它总是多次返回EAGAIN。所以我的重试将失败。 因为服务器需要处理数千个客户端事件,所以我认为让重试总是继续是一个巨大的性能消耗,这是不可

我使用epoll实现TCP套接字通信以监视所有客户端事件,在for循环中只有一个线程处理所有客户端。每个插座都是非阻塞的

现在我遇到了一个问题,当客户端发送的数据超过MTU,意味着几个片段数据包时,服务器总是无法完全读取所有数据。 如下图所示,我首先读取头部,从头部获取pdu透镜,然后读取pdu部分

问题是,虽然我成功地读取了头部,紧跟着pdu recv,但它总是多次返回EAGAIN。所以我的重试将失败。 因为服务器需要处理数千个客户端事件,所以我认为让重试总是继续是一个巨大的性能消耗,这是不可容忍的

我使用tcpdump从客户机捕获数据包,每个数据包都是最大1448字节的数据片段,但是head只有5字节,为什么我可以成功读取head,但是下面的数据recv操作将返回EAGAIN?当数据已经到达recv缓冲区时,recv是否可能返回EAGAIN?在我看来,我可以读取前5个字节,因此必须在recv缓冲区中读取更多数据

可能与tcp/ip堆栈中的组装过程有关。 代码如下,每个pdu recv,需要10次或更多重试,可能成功

...
#define HDR_LEN    5
n = epoll(epfd, events, 1000, -1)
for(i =0; i < n; i++)
{
    uint8 pHdr[HDR_LEN] = {0};
    uint16 pdulen = 0, offset =0;
    infd = events[i].fd;
    nRead = recv(infd, pHdr, HDR_LEN);   // read the data head first
    pdulen = ntohs(*(uint16 *)(pHdr+2));   // get the pdu len from the head
    uint8 *pbuf = malloc(pdulen+HDR_LEN);

    memcpy(pbuf, pHdr, HDR_LEN);            // move the head to buf
    while(offset != pdulen)                 // then read the pdu data
    {
        nRead = recv(infd, pbuf+HDR_LEN+offset, pdulen-offset);
        if (nRead <=0)
        {
            if (nRead == -1 && errno == EAGAIN) // resource temporarily unavailable 
            {
                if (retry < 5)
                {
                    usleep(500);
                    retry++;
                    continue;
                }
                else
                     break;  // already try 5 times, should always continue?
            }
            else
                break;
        }
        else
        {
             offset += nRead;
             retry = 0;
        }
    }
    if (offset == pdulen)
        process(pbuf, pdulen+HDR_LEN); // process the complete data
    ...
}
...
epoll将告诉您是否可以在不阻塞的情况下接收一次。如果recv使用了来自套接字的所有数据,则下一个recv将阻塞,直到有更多数据,或者如果没有阻塞套接字,则返回EAGAIN

常见的模式是:

使用select/poll/epoll检测何时可以读取套接字。 在就绪套接字上调用recv一次,并将接收到的数据附加到缓冲区。 检查缓冲区是否包含足够的数据进行处理。如果是,则处理。否则,让select/poll/epoll告诉您何时可以阅读更多内容。
请帮帮我,帮我解决这个问题!您的套接字是否处于非阻塞模式?如果是这样的话,那么只要接收缓冲区中没有更多的数据可供检索,就会出现EAGAIN。为了同时处理多个套接字的非阻塞I/O,您需要实现一个状态机,以便在收到部分响应后可以返回正常的轮询调用。然后,当poll显示套接字上有更多数据要读取时,您应该返回并从套接字中重新获取附加数据,将其附加到以前从该套接字获取的数据中,直到获得整个PDU。tcp套接字重新获取是否会返回“resource Temporary unavailable”(资源暂时不可用)recv buf何时已经有数据?否。