如何写入非阻塞套接字(使用 epoll 时)
How to write to a nonblocking socket (when using epoll)
当在非阻塞套接字上使用 epoll 执行异步套接字 IO 时,读取似乎很简单:只需 epoll_wait
直到套接字准备好读取,然后读取直到获得 EAGAIN
/EWOULDBLOCK
.
但是怎么发送呢?大概做一个大的 send
操作会阻塞,所以你总是会得到 EAGAIN
/EWOULDBLOCK
。你打算做什么?
大概内核将无法立即发送所有数据,这就是为什么send
on success returns the number发送的字节数。重要的是返回的数字 可以 (并且很可能会)小于调用中指定的总长度。如果 根本没有字节 可以发送,您只会得到 EAGAIN/EWOULDBLOCK
作为答复。所以当发送大量数据时,你只需要正确处理(很有可能)不是所有数据都一次发送的可能性。
注意:这与数据报 (UDP) 套接字不同,因为无法发送部分数据报。有关详细信息,请参阅 。
这是一个假设 SOCK_STREAM
(TCP) 套接字的示例:
size_t len;
size_t sent;
char *buf;
/* ... prepare data ... */
while (sent < len) {
ssize_t n;
if ((n = send(sockfd, buf + sent, len - sent, flags)) == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue;
} else {
perror("send failed");
exit(1);
}
}
sent += n;
}
send/to()
将发送尽可能多的字节,返回它实际能够让内核发送多少字节。
如果您使用的是 TCP 套接字,请循环调用 send()
,直到您的所有字节都已发送或报告 EAGAIN
/EWOULDBLOCK
。在后一种情况下,停止循环并将剩余的字节缓存在某处。
如果你使用的是UDP套接字,send/to()
只能发送整个数据报,所以根本不要使用循环,如果报告EAGAIN
/EWOULDBLOCK
那么缓存整个数据报。
每当 epoll
指示套接字可写时,根据需要为该套接字发送任何缓存的 bytes/datagrams,仅从缓存中删除成功的 bytes/datgrams,直到清除缓存或报告 EAGAIN
/EWOULDBLOCK
。在缓存中保留未发送 bytes/datagrams。
每当您需要发送新的 TCP 字节或新的 UDP 数据报时,如果套接字的缓存不为空,则将 bytes/datagram 附加到缓存的末尾并继续,否则尝试发送bytes/datagram 立即,如果报告 EAGAIN
/EWOULDBLOCK
则缓存,如上所述。
当在非阻塞套接字上使用 epoll 执行异步套接字 IO 时,读取似乎很简单:只需 epoll_wait
直到套接字准备好读取,然后读取直到获得 EAGAIN
/EWOULDBLOCK
.
但是怎么发送呢?大概做一个大的 send
操作会阻塞,所以你总是会得到 EAGAIN
/EWOULDBLOCK
。你打算做什么?
大概内核将无法立即发送所有数据,这就是为什么send
on success returns the number发送的字节数。重要的是返回的数字 可以 (并且很可能会)小于调用中指定的总长度。如果 根本没有字节 可以发送,您只会得到 EAGAIN/EWOULDBLOCK
作为答复。所以当发送大量数据时,你只需要正确处理(很有可能)不是所有数据都一次发送的可能性。
注意:这与数据报 (UDP) 套接字不同,因为无法发送部分数据报。有关详细信息,请参阅
这是一个假设 SOCK_STREAM
(TCP) 套接字的示例:
size_t len;
size_t sent;
char *buf;
/* ... prepare data ... */
while (sent < len) {
ssize_t n;
if ((n = send(sockfd, buf + sent, len - sent, flags)) == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue;
} else {
perror("send failed");
exit(1);
}
}
sent += n;
}
send/to()
将发送尽可能多的字节,返回它实际能够让内核发送多少字节。
如果您使用的是 TCP 套接字,请循环调用 send()
,直到您的所有字节都已发送或报告 EAGAIN
/EWOULDBLOCK
。在后一种情况下,停止循环并将剩余的字节缓存在某处。
如果你使用的是UDP套接字,send/to()
只能发送整个数据报,所以根本不要使用循环,如果报告EAGAIN
/EWOULDBLOCK
那么缓存整个数据报。
每当 epoll
指示套接字可写时,根据需要为该套接字发送任何缓存的 bytes/datagrams,仅从缓存中删除成功的 bytes/datgrams,直到清除缓存或报告 EAGAIN
/EWOULDBLOCK
。在缓存中保留未发送 bytes/datagrams。
每当您需要发送新的 TCP 字节或新的 UDP 数据报时,如果套接字的缓存不为空,则将 bytes/datagram 附加到缓存的末尾并继续,否则尝试发送bytes/datagram 立即,如果报告 EAGAIN
/EWOULDBLOCK
则缓存,如上所述。