繁体   English   中英

当recv buf已经有数据时,tcp socket recv将返回“资源暂时不可用”

[英]will tcp socket recv return “resource temporarily unavailable” when recv buf already have data

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

现在我只是遇到一个问题,当客户端发送的数据超过MTU时,意味着有多个片段数据包,服务器始终无法完全读取所有数据。 像下面一样,我先读头,从头获得pdu len,然后阅读pdu部分。

问题是尽管我成功地读取了磁头,紧跟着pdu recv(),但是它总是多次返回EAGAIN。 所以我的重试会中断。 因为服务器需要处理成千上万的客户端事件,所以我认为让重试始终继续是很大的性能消耗,这是不能容忍的。

我使用tcpdump捕获来自客户端的数据包,每个数据包都是最大1448字节数据的片段,但是head只有5个字节,为什么我可以成功读取head,但是以下数据recv()操作将返回EAGAIN? 当数据已经到达接收缓冲区时,接收返回是否可能返回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消耗了套接字中的所有数据,则下一个recv将阻塞,直到有更多数据为止,否则返回EAGAIN(如果是非阻塞套接字)。

常见的模式是:

  1. 使用select/poll/epoll检测何时可以读取套接字。
  2. 在就绪套接字上调用一次recv ,然后将接收到的数据附加到缓冲区中。
  3. 检查缓冲区是否包含足够的数据以进行处理。 如果是,则进行处理。 否则,请让select/poll/epoll告诉您何时可以阅读更多内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM