这次思考的原因:
有一次项目组开会,有人提出了一个问题,当tcp层给他的模块一个字节,一个字节的提供数据的时候可能会导致他的模块出问题,我不理解的地方tcp会有一个字节一个字节向上提供数据么?如果有,什么情况下会有。会有自己在仔细的想了一下,就是当我们开发时,调用send()函数之后究竟发生了什么?我们根本不知道。
经过思考和查找大量资料之后的总结:
当我们创建基于tcp的socket连接时候,操作系统会为这条socket连接建立一条发送缓存去和一条接收缓冲区,这个缓冲区是有上限值的,当我们调用send()函数后,其实是把数据从应用程序拷贝到系统的发送缓冲区然后就返回了。然后tcp层会对消息进行封装通知下一次,最后通过网卡发送出去,当tcp层还没有收到对端的应答的时候,我们又多次调用了send()函数,就会有多条数据添加到发送缓存区了,当tcp层收到对端的应答的时候,会从发送缓存区取出小于mss值的数据段然后继续发送,这个时候就会有多个消息合成一个数据段发送出去。这就是所谓的粘包。由于缓存区大小是有上限值的,对端(接收端)也是一样。如果对端接收端的处理比较缓慢,接收缓存区很快就满了,为了避免大量无效的数据发送,tcp会进行流控制,就是在应答的消息头中会带有缓冲区剩余大小,就是所谓的窗口大小,之后发送端会根据这个窗口大小值发送发送数据段,所有对端接收缓冲区剩余大小是可能剩余为1的,但是一直剩余为1不太可能,除非上层1个字节1个字节的从缓存区拷数据。所有tcp层应该不会1个字节1个字节向上层提供数据,除非你上层接收数据的方式是1个字节1个字节的从接收缓存区拷贝读取。数据的传输过程中还受到拥塞控制。就是tcp为了防止网络拥塞导致大量包重发,增加了拥塞控制,就是在发送数据包的时候,会先设置一个比较小的值,这个值和窗口值做比较,取较小的一个,随着发送数据包次数增加,这个拥塞控制值会成倍的增加。当有数据重发的时候又从默认值开始。不过我个人觉得,这个拥塞控制值应该只会影响开始启动或有重发的时候,而且也不会从1个字节开始。
网友评论