每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。如下图所示:
图片说明

在上一节的例子中,我们通过write函数给客户端的套接字写了一些数据,但是呢,写的这些数据并不是立即发送到客户端的,而是先写入一个输出缓冲区,如上图所示,然后函数就返回了。那么又是由谁来把这些数据发送到远程主机的呢?当然是我们的TCP协议啦。所以我们之前那个测试程序有时候客户端会读不到服务端发过来的消息,正是由于服务端写的数据还在输出缓冲区当中,并没有被发送到客户端的输入缓冲区,所以客户端这个时候去读数据是读不到滴,会被阻塞。

缓冲区特性:
a.I/O缓冲区在每个TCP套接字中单独存在
b.I/O缓冲区在创建套接字时自动生成
c.即使关闭套接字也会继续传送输出缓冲区中遗留的数据
d.关闭套接字丢失输入缓冲区中的数据

阻塞状态:
使用TCP套接字,使用write发送数据时:
a.如果我们write的数据比较多,大于当前输出缓冲区的数据的时候,会如何呢?这种情况我们的write函数是会进入阻塞状态的。直到缓冲区腾出了足够的空间,才会被唤醒。

b.如果write写的数据大于整个缓冲区的最大长度呢?答案是会分批写入,直到write写的数据全部被写入到了缓冲区,write函数才会返回。

c.如果TCP协议正在发送数据,那么缓冲区会被锁定,此时如果执行到write函数,这时候是会被阻塞的,直到TCP把数据发送完。

使用TCP套接字,使用read接收数据时:
a.首先会检查缓冲区,如果缓冲区中有数据,那么就读取,否则read函数会被阻塞,直到网络上有数据到来。

b.如果要读取的数据长度小于缓冲区中的数据长度,那么就不能一次性将缓冲区中的所有数据读出,剩余数据将不断积压,直到有 read()函数再次读取。

c.直到读取到数据后 read()函数才会返回,否则就一直被阻塞。

d.这就是TCP套接字的阻塞模式。所谓阻塞,就是上一步动作没有完成,下一步动作将暂停,直到上一步动作完成后才能继续,以保持同步性。