除了缓冲区已满,EAGAIN 会在发送时返回吗?

Posted

技术标签:

【中文标题】除了缓冲区已满,EAGAIN 会在发送时返回吗?【英文标题】:Will EAGAIN return on send for anything other than buffer full? 【发布时间】:2011-03-05 10:47:36 【问题描述】:

如果我在 Linux 中的非阻塞 tcp 套接字上使用 send(),它是否会返回 EAGAIN,而不是发送缓冲区已满?

我基本上需要决定是要使用套接字发送缓冲区作为我的应用程序的唯一缓冲区,还是需要我自己的用户空间缓冲区来提供套接字缓冲区。

【问题讨论】:

【参考方案1】:

不应该,但我看不出这会以何种方式影响您对用户空间缓冲区的决定。无论获得 EAGAIN 的具体原因如何,您是否需要缓冲区都取决于您的应用正在做什么。

在进行一些计算后,您还可以考虑使用setsockopt 和 SO_SNDBUF 选项更改 tcp 缓冲区大小,看看这是否真的是性能上的赢家。

【讨论】:

【参考方案2】:

如果我在 Linux 中的非阻塞 tcp 套接字上使用 send(),它是否会返回 EAGAIN,而不是发送缓冲区已满?

在应该是唯一条件的非阻塞套接字上,因为 send() 仅在发送缓冲区已满时阻塞。

否则,我建议不要依赖这种行为,因为根据我的经验,EAGAIN 有时会在内核中出现一些小故障时返回,但套接字仍然可以。我最近在返回 EAGAIN 时体验了 HP-UX,因为显然内核内存不足。由于错误是可恢复的,因此 EAGAIN 是该案例可接受的错误代码。

【讨论】:

【参考方案3】:

当未确认的数据包数量达到拥塞窗口时,也可以返回 EAGAIN/EWOULDBLOCK(对于 TCP 套接字)。

检查套接字 w.r.t 的状态。拥塞窗口,然后试试这个:

#include <netinet/tcp.h>
static void print_tcp_cwnd(int socket)

    struct tcp_info tcp_info;
    uint tcp_info_length = sizeof(tcp_info);
    if ( getsockopt( socket, SOL_TCP, TCP_INFO, (void *)&tcp_info, &tcp_info_length ) == 0 ) 
    
        printf("tcpi_snd_cwnd: %u, tcpi_unacked: %u\n",
            tcp_info.tcpi_snd_cwnd,
            tcp_info.tcpi_unacked
           );
    

如果tcpi_unacked == tcpi_snd_cwnd 则 send() 将为非阻塞套接字返回 EAGAIN/EWOULDBLOCK。

【讨论】:

以上是关于除了缓冲区已满,EAGAIN 会在发送时返回吗?的主要内容,如果未能解决你的问题,请参考以下文章

POSIX - 理解非阻塞发送实现

在读取缓冲区已满时使用 select 检查可写套接字

ALSA:snd_pcm_writei 返回 EAGAIN

usrsctp 发送缓冲区不会自行释放

linux串口发送时与上次不冲突

linux非阻塞的socket EAGAIN的错误处理