1、socket默认是阻塞的,阻塞时:

send函数

如果可用空间大小小于要发送的数据长度,则send会被阻塞,直到缓冲区中的数据被发送到目标主机,有了足够的空间之后,send函数才会将数据写入输出缓冲区。

要写入的数据大于输出缓冲区的最大长度的时候,要分多次写入,直到所有数据都被写到缓冲区之后,send函数才会返回。

recv函数

函数先检查输入缓冲区,如果输入缓冲区中有数据,读取出缓冲区中的数据,否则的话,recv函数会被阻塞,等待网络上传来数据。如果每次读取的数据长度小于buffer的数据长度,没法一次性将所有数据读出来,需要多次执行recv函数,才能将数据读取完毕。

2、socket设置为非阻塞态时:

send函数

如果事件正常发生,则跟阻塞态一样,如果出现错误情况,如,可用空间大小小于要发送的数据长度,则不会被阻塞,而是直接返回,通过错误代码来查看错误原因。

recv函数

即使缓冲区中无数据,也不会阻塞,而是直接返回。

3、说明

socket默认是阻塞的,即recv或者send或者accept函数在没有事件发生时,都是阻塞的。

阻塞的socket使用起来简单,不用判断EAGAIN(EWOULDBLOCK)或者EINTR错误,并且对于recv函数,在输入缓冲区没有数据读或

者缓冲区数据少于要取的buff长度时,会阻塞;对于send函数,在发送缓冲区剩余空间小于发送的buff长度时,会阻塞;

阻塞的时候,线程处于sleep休眠状态,此时不占用CPU,CPU就可以调度别的线程或进程,这是阻塞态socket的优点;

socket也可以使用fcntl函数修改属性为非阻塞的.阻塞态socket的优点对应的就是非阻塞socket的缺点,即如果所有设备都一直没有数据到达,调用者需要反复查询做无用功,如果阻塞在那里操作系统可以调度别的进程执行,就不会做无用功了。select 函数可以阻塞地同时监视多个设备(即select的timeout参数设置为NULL),还可以设定阻塞等待的超时时间(timeout参数设置为一个正数,比如3s,3s内没有事件发生,则线程也是sleep了3s),从而圆满地解决了这个问题。