了解非阻塞套接字上的 EWOULDBLOCK

Posted

技术标签:

【中文标题】了解非阻塞套接字上的 EWOULDBLOCK【英文标题】:Understanding EWOULDBLOCK on non blocking sockets 【发布时间】:2014-02-23 13:38:26 【问题描述】:

我正在尝试从远程 GUI 应用程序访问路由器上的系统日志消息。基本上,路由器上的 WEB 服务器打开 syslog 文件(/var/log/messages),读取所有日志消息并尝试根据用户请求通过此 WEB 套接字将其发送到客户端 GUI 应用程序。它是一个非阻塞套接字。所以我观察到当消息数量很大时(发送缓冲区的大小很大),在调用 send() 调用时,它总是返回 -1 并出现错误 EWOULDBLOCK。我多次尝试重新发出呼叫,结果相同。这是否意味着 TCP/IP 堆栈上的发送缓冲区已满?那么如何避免呢?我什至观察到,当发送缓冲区较少时, send() 正在成功发送数据。 感谢您提前回复?

【问题讨论】:

如果您的套接字是非阻塞的,您需要轮询它并响应“准备写入”事件。同时,您需要自己排队要发送的数据。 @Kerrek 感谢您的回复。我也在做同样的事情。我正在维护一个 fifo 并等待 FD_WRITE 事件。向用户空间发出这个事件的信号需要多少时间/条件? TCP/UDP 发送缓冲区的大小是有限的。如果您尝试发送大于发送缓冲区的send() 消息,send() 将始终返回 EWOULDBLOCK。也许尝试将日志消息拆分为保证不超过 TCP/UDP 发送缓冲区的块。您可以调整缓冲区的大小(在setsockopt() 的限制范围内)。 【参考方案1】:

您可以将发送者缓冲区设置为大尺寸:

int                     sendbuf         = -1; /* -1 will give a maximum allowed buffer size you can use any larger number */
rc = setsockopt(sd, SOL_SOCKET, SO_SNDBUF,(char *)&sendbuf, sizeof(sendbuf));
if(rc < 0)
          printf(("Setting SO_SNDBUF error, %s",strerror(errno)));
          return -1;

为避免 EWOULDBLOCK(当发送缓冲区已满时会发生此错误),您应该使用 iomux(epoll、poll 或 select) 此外,当尝试接收时接收缓冲区为空时,也会发生此错误。

【讨论】:

没有这个限制。您可以发送任何大小的数据。 TCP 将根据路径 MTU 将其打包,但这不会以任何方式影响发送应用程序。 @EJP 我的意思是,当您发送 datalen>64KB EMSGSIZE 的消息时... datalen=65536;databuf = malloc(sizeof(char) * datalen); memset(databuf, 0, datalen); rc = sendto(sd, databuf, datalen, 0); 仅在 UDP 中。问题中没有提到UDP。准确地说,最大 UDP 有效负载为 65507。 对不起,我应该提到在 UDP 上,是的 65507+28headers=64kb 又错了。 65507+28=65535,不是 64kb。而且这些 UDP 内容都与该问题没有任何明显的相关性。

以上是关于了解非阻塞套接字上的 EWOULDBLOCK的主要内容,如果未能解决你的问题,请参考以下文章

没有 ConnectEx 的 Windows 上的非阻塞套接字连接

阻塞和非阻塞同步和异步

非阻塞套接字与IO多路复用

为啥非阻塞套接字在connect() 或accept() 之前是可写的?

windows下在非阻塞TCP套接字上使用SO_SNDBUF的奇怪行为

异步非阻塞socket的实现