阻塞和非阻塞:
在网络编程中对于一个网络句柄会遇到阻塞IO和非阻塞IO的概念,这里对于两种socket先做一下说明:
阻塞IO:socket的阻塞模式意味着必须要做完IO操作(包括错误)才会返回(默认是阻塞的)
例如:服务器端调用recvfrom,如果没有客户端没有发送数据,此时recvfrom处于阻塞态,就会一直阻塞下去
非阻塞IO:非阻塞模式下无论操作是否完成都立刻返回,需要通过其他方式来判断具体操作是否成功。(对于connect,accept操作,通过select判断,对于recv,recvfrom,send,sendto通过返回值+错误码来判断)
IO模式设置:
对于一个socket是阻塞模式还是非阻塞模式的处理方法:
用fcntl设置;F_GETFL获取flags,用F_SETFL设置flags|O_NONBLOCK;
同时,recv,send时使用非阻塞的方式读取和发送消息,即flags设置为MSG_DONTWAIT
代码实现:
fcntl函数可以将一个socket句柄设置成非阻塞模式:
flags = fcntl(sockfd,F_GETFL,0); //获取文件的flags值
fcntl(sockfd,F_SETFL,flags | O_NONBLOCK); //设置成非阻塞模式
设置成阻塞模式:
flags = fcntl(sockfd,F_GETFL,0);
fcntl(sockfd,F_SETFL,flags&~O_NONBLOCK) //设置成阻塞模式
并在接受和发送数据的时候讲recv和send函数的最后一个flag参数设置成MSG_DONTWAIT
recv(sockfd,buff,buff_size,MSG_DONTWAIT)//非阻塞模式的消息接收
send(sockfd,buff,buff_size,MSG_DONTWAIT)//非阻塞模式的消息发送
对于文件的阻塞模式还是非阻塞模式:
方法1:open时,使用O_NONBLOCK;(非阻塞模式)
方法2:fcntl设置,使用F_SETFL,flags|O_NONBLOCK
对于消息队列消息的发送与接收:
发送:msgsnd(sockfd,msgbuf,msgsize,IPC_NOWAIT)
接收:msgrcv(sockfd,msgbuf,IPC_NOWAIT)
读操作的阻塞与非阻塞:
阻塞的区别在于是否立刻返回。
读的本质来说其实不能是读,在实际中,具体接收数据不是由这些调用来进行,是由系统底层自动完成的。read也好,recv也好只负责把数据从底层缓冲copy到我们制定的位置
阻塞情况:
在阻塞条件下,read/recv/msgrcv的行为:
1.如果没有发现有数据在网络缓存中会一直等待;
2.当发现有数的时候会把数据读到用户指定的缓冲区,但是如果这个时候读到的数据量比较少,比参数中指定的长度要小,read并不会一直等待下去,而是立刻返回。
read的原则:是数据在不超过指定的长度的时候有多少读多少,没有数据就会一直等待
所以一般情况下:我们读取数据都需要采用循环的方式读取数据,因为一次read完毕不能保证读到我们需要长度的数据,read完一次需要判断读到的数据长度再决定是否还需要再次读取
非阻塞状态下
1. 如果发现没有数据就直接返回
2. 如果发现有数据那么也是采用有多少读多少的进行处理,所以read完一次需要判断读到的数据长度再决定是否还需要再次读取
总结:对于读操作来说,阻塞与非阻塞的区别在于没有数据到达的时候是否立刻返回