专栏其他文章:
理论篇:
(一)深入浅出TCPIP之理解TCP报文格式和交互流程
(二)深入浅出TCPIP之再识TCP,理解TCP三次握手(上)
(三)深入浅出TCPIP之再识TCP,理解TCP四次挥手(上)
(四)深入浅出TCPIP之TCP三次握手和四次挥手(下)的抓包分析
(五)深入浅出TCPIP之TCP流量控制
(六)深入浅出TCPIP之TCP拥塞控制
(七)深入浅出TCPIP之深入浅出TCPIP之TCP重传机制
(八)深入浅出TCPIP之TCP长连接与短连接详解
(九)深入浅出TCPIP之网络同步异步
(十)深入浅出TCPIP之网络阻塞和非阻塞
(十一)深入浅出TCPIP之TCP粘包问题
(十二)深入浅出TCPIP之Nagle算法
(十三) 深入浅出TCPIP之TCP套接字参数
(十四)深入浅出TCPIP之初识UDP理解报文格式和交互流程
(十五)非常全面的TCPIP面试宝典-进入大厂必备总结
(十六)深入浅出TCPIP之Hello CDN
....
(二十)深入浅出TCPIP之epoll的一些思考
实践篇:
深入浅出TCPIP之实战篇—用c++开发一个http服务器(二十一)
其他实践篇+游戏开发中的网络问题疑难杂症解读 正在完善。。。
阻塞和非阻塞 强调的是程序在等待调用结果(消息,返回值)时的状态. 阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。 对于同步调用来说,很多时候当前线程还是激活的状态,只是从逻辑上当前函数没有返回而已,即同步等待时什么都不干,白白占用着资源。
大部分高性能网络框架采用的是非阻塞模式。笔者这次就从linux源码的角度来阐述socket阻塞(block)和非阻塞(non_block)的区别。 本文源码均来自采用Linux-2.6.24内核版本。
如果我们要产生一个非阻塞的socket,在C语言中如下代码所示:
// 创建socket
int sock_fd = socket(AF_INET, SOCK_STREAM, 0);
...
// 更改socket为nonblock
fcntl(sock_fd, F_SETFL, fdflags | O_NONBLOCK);
// connect
....
while(1) {
int recvlen = recv(sock_fd, recvbuf, RECV_BUF_SIZE) ;
......
}
...
在这里我们使用fcntl控制socket的阻塞\非阻塞状态
事实上:
fcntl的作用就是将O_NONBLOCK标志位存储在sock_fd对应的filp结构的f_lags里,当调用recv的时候,recv的底层调用sock_recvmsg
值得注意的是,在sock_recmsg中,有对标识O_NONBLOCK的处理
if (sock->file->f_flags & O_NONBLOCK)
flags |= MSG_DONTWAIT;
上述代码中sock关联的file中获取其f_flags,如果flags有O_NONBLOCK标识,那么就设置msg_flags为MSG_DONTWAIT(不等待)。
fcntl与socket就是通过其共同操作File结构关联起来的。
这里O_NONBLOCK和O_NDELAY所产生的结果都是使I/O变成非阻塞模式(non-blocking),在读取不到数据或是写入缓冲区已满会马上return,而不会阻塞等待。
它们的差别在于:在读操作时,如果读不到数据,O_NDELAY会使I/O函数马上返回0,但这又衍生出一个问题,因为读取到文件末尾(EOF)时返回的也是0,这样无法区分是哪种情况。因此,O_NONBLOCK就产生出来,它在读取不到数据时会回传-1,并且设置errno为EAGAIN。