1.基本概念
所谓的阻塞,即内核在对文件操作I/O系统调用时,如果条件不满足(可能需要产生I/O),则内核会将该进程挂起。非阻塞则是发现条件不满足就会立即返回。此外需要注意的是非阻塞并不是轮询,不然就和阻塞没多大区别了,它只是调用不成功就直接返回了,不会在去看啥时候会满足条件,而是有你自己去选择接下来该咋办,系统以不再负责
2.read/write阻塞与非阻塞的理解
read/write系统调用,并不会去直接读写文件,而只是去操作文件所对应的内存页(此时的页为虚拟内存),对于read如果在页中找到了想要读写的数据,则直接从页中将数据copy到用户缓存即可,如果要读的页没有找到,则只能从磁盘读出该页内容缓存在内存中即可。所谓的读过程,其实文件系统所要做的只是锁定页面,然后构造一个读请求,并将请求发给底层的IO子系统即可。linux内核中read系统调用默认是阻塞的write调用是非阻塞的,因为write时只是将用户态的数据写入缓存页面中即可返回
3.对于网络套接字阻塞/非阻塞对读数据的影响
(1)在阻塞情况下
在阻塞条件下,read/recv/msgrcv的行为
1.如果没有发现数据在网络缓冲中会一直等
2.当发现有数据时会把数据读到用户指定的缓存区中(如果读到的数据比指定的大小小,read此时并不会阻塞,而是会立即返回)
应为read的原则是在不超过指定长度的时候有多少读多少,没有数据就返回。所以一般情况下,如果我们想要读取我们想要的字节量,就得循环read
(2)在非阻塞情况下
在非阻塞情况下read的行为
1.如果发现没有数据就直接返回
2.如果发现有数据,那么也是采用有多少就读多少,所以read完之后需要判断是否再次进行read操作,以读到我们想要的字节数
对于读的阻塞与非阻塞区别就在于没有数据可读时,是否立即返回
4.对于网络套接字阻塞/非阻塞对写数据的影响
写的操作本质也不是进行发送操作,而是把用户态的数据copy到系统底层去,然后由系统帮忙发送。send,write返回成功,只表明数据已经copy到底层缓冲,而并不表明数据以发送出去,更不能表示对方端口已经接收到数据
(1)阻塞情况下
write会将数据发完之后才返回,这里与读不同。当我们读数据的时候,我们并不知道发送端是否还有数据要发,如果一直等待就可能造成死循环,所以为了避免这类事情发生,我们把当前缓存中的内容读完,就返回了,并不关心是否读够了我们想要读的字节数。而write,由于需要写的长度是知道的,所以它会一直写够指定的字节才返回
(2)非阻塞情况下
非阻塞情况下,是采用可以写多少就写多少的策略,与读不一样的地方在于,有多少读多少是由网络发送端是否有数据传输到为标准。但是对于写多少是由本地网络堵塞情况为标准的,对于非阻塞的情况就是一次写多少算多少,有可能会造成部分写入