(十)深入浅出TCPIP之网络阻塞和非阻塞

专栏其他文章:

 

理论篇:

(一)深入浅出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内核版本。

一个TCP非阻塞client端简单的例子

如果我们要产生一个非阻塞的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。

 

 

你可能感兴趣的:(深入浅出TCP/UDP,网络)