C++网络通信中write和read的为什么会阻塞

最近在看一些阻塞式IO的系统调用函数read和write,今天在这里写一篇文章说明下为什么会发生阻塞。

首先我们知道对于使用TCP协议进行通信的双方,各自都会有一个发送缓冲区(send buffer)接收缓冲区(receive buffer),这两个缓冲区都是有大小的,发生阻塞的本质原因就是因为缓冲区满了。接下来我们分别对write函数和read函数来进行说明为什么会阻塞。

write函数

函数原型:size_t write(int fd, char *buf, size_t n);//将内存中buf中的数据发送给fd指向的文件,最多发送n的字节数据。返回实际发送字节的个数。

write函数原理:write函数只是将内存中buf中的内容拷贝到内核中TCP发送缓冲区中,接下来什么时候将TCP发送缓冲区的数据发出给对方主机,什么时候被对方主机读取,这些是我们无法控制的。

我们知道TCP是一个提供可靠数据传输的协议,发送端需要收到已收到的报文的确认消息。也就是说,发送端将内核send buffer中的数据发送到网络后并不会立刻清除send buffer,必须等待收到对方主机的确认信息后才会清除。

接收端从套接口(sockfd)中接收数据后放入到自己的receive buffer中,并对receive buffer中的数据返回一个确认信息。发送端收到对数据的ack后才会清除自己的send buffer。如果接收端没有将receive buffer中的数据及时确认清除而导致receive buffer中的数据填满,由于滑动窗口协议的作用,接收端不会再从socket上读取数据,进而给发送端返回的报文中会阻止发送端发送数据。

发送端仍然发送数据,直到发送端的send buffer被填满,write函数被阻塞。

在每个TCP报文中,都会有一个字段叫cwd:来告知对方自己receive buffer(窗口)的大小,对方收到报文后会根据cwd来判断是否还要发送数据。

总结:用一句话来说就是,接收端接受数据的速度赶不上发送端发送数据的速度,接收端通过报文中的cwd告诉发送端不要再发送数据了,send buffer被填满而引发阻塞。



read函数

函数原型:size_t read(int fd, char*buf, size_t n);//从fd文件中读取n个字节的数据到内存buf中。

功能:read函数就是将内核中TCP接收缓冲区(receive buffer)中的数据拷贝到内存数组buf中。

阻塞原理:read函数发生阻塞,是因为TCP的receive buffer中没有数据。也就是说发送端的数据还没有发送过来。


write和send的行为区别

当TCP的接收缓冲区中有数据的话,read就会对数据进行拷贝,而不是等到receive buffer中被填满时才会拷贝。

而write却不同,只有当TCP的send buffer中能够存放内存buf的内容时才会将buf拷贝到send buffer中。


整个通信过程中,任意一方都会有三个缓冲区:内存中存放数据的一个缓冲区,用于TCP通信的发送缓冲区(send buffer)和接受缓冲区(receive buffer),通过报文中cwd来控制传输的数据量。

  • 10
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值