1. no-blocking
将socket设置为no-blocking意味着socket收发数据都是非阻塞的,相比于阻塞方式,需要特殊处理这个错误码:EWOULDBLOCK or EAGAIN(这两个错误码是一样的,都是35),进行重试或者重新调度。
将socket设置非阻塞有多种方法,下面会一一汇总。
1.1 fcntl设置O_NONBLOCK
POSIX的fcntl用的比较广泛,兼容性也比较好,优先推荐使用fcntl来设置,缺点是需要两次系统调用:get、set:
/* Change the socket into non-blocking state F_SETFL is a command saying set flag and flag is 0_NONBLOCK */
const int flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) {
return flags;
}
if (flags & O_NONBLOCK) {
return 0;
}
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
1.2 使用socket自带的函数
该方法优点是简单,缺点是兼容性不太好,要求Linux内核版本高于2.6.27才可以使用:
// client side
int socketfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
// server side - see man page for accept4 under linux
int socketfd = accept4( ... , SOCK_NONBLOCK);
1.3 ioctl设置FIONBIO
ioctl最先在UNIX系统上使用,跨平台兼容性比较差,各个系统中该系统调用的行为是不一致的,不建议使用该方式:
int opt = 1;
int status = ioctl(fd, FIONBIO, &opt);
2. no-delay
Nagle算法是为了减少更多的网络小数据包:如果数据小于一个限制(通常是MSS),等待接收到之前发送的数据包的ACK,在同一时间内积累用户的数据,然后发送累积的数据。
Nagle算法有助于像telnet这样的应用程序。然而,等待ACK可能会增加发送流数据时的延迟。此外,如果接收方实现了“延迟确认策略”,它将导致临时的死锁情况。在这种情况下,禁用Nagle的算法是更好的选择,可以通过设置TCP_NODELAY禁用Nagle算法。
int opt = 1;
int status = setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
3. ref
- https://stackoverflow.com/questions/1543466/how-do-i-change-a-tcp-socket-to-be-non-blocking/22339017
- http://senlinzhan.github.io/2017/02/10/Linux%E7%9A%84TCP-CORK/