tcp协议的面向字节流介绍,粘包问题(解决的本质)

目录

面向字节流

引入

介绍

比喻

处理数据 

粘包问题

引入

介绍

解决的本质


面向字节流

引入

对于udp来说,它是面向数据报的

  • 一旦要发送数据,因为没有发送缓冲区,且不需要维护连接,直接封装完报头就发出去了
  • 依靠报头中的udp长度字段,可以拆分出报文然后交付给上层
  • 一个报文里就是一次响应/请求的全部数据

但是对于tcp协议来说

  • 它需要维护一个持续的连接,数据也就得是连续的
  • 并且他有两个缓冲区,所以读写操作不需要一一匹配
  • 比如,一次写了100字节,然后分10次读 / 分10次写完100字节,一次读出,这都是可以的
  • 它可以根据需要,写入/读取任意长度的数据,tcp会负责将这些数据分割成合适大小的报文段进行传输

 

介绍

对于tcp来说,假设我们发送了4个请求给对方:

  • 应用层看来,是4个请求报文
  • 但从传输层看来,这些只是若干个字节数据,它只保证如何安全地可靠地将这些数据发送给对方,并且发送的数量不定,由对方的接收能力决定
  • 当对方的传输层接收到后,也同样只认识字节,它不管,它只管往上交付若干字节

所以,实际上只有用户层有报文的概念

在传输层看来:

  • 就是有若干字节数据进缓冲区->出缓冲区->进缓冲区->出缓冲区
  • 于是就有了字节流动的概念,这就叫面向字节流 

比喻

其实面向字节流很像水流

  • 传输层是一条水管,它不管水是哪来的,只管运输
  • 另一方无论是用杯子接,用盆接都行,接多少都行,只要还有水

处理数据 

但交付的这些字节并不能保证就是一份报文

  • 所以需要在应用层定义一个缓冲区一直读,边读边对数据进行解析(要么不读,要么就读上来一份完整的数据)
  • 解析成功后就拿走,剩下的继续重复上述步骤

我们在网络计算器里也正是这样做的

  • 这些处理属于我们之前的encode/decode范畴,和序列化/反序列化有上下层关系

但是边读边解析效率比较低

  • 我们已经介绍过tcp的传输控制机制,能知道 -- 如果自己的接收窗口更大,对方就会动态调整自己的滑动窗口大小,可以传过来更多的数据,可以提高传输效率
  • 所以,我们最好是一有数据就全部读到用户层,再慢慢处理

 

粘包问题

引入

如果它没有制定协议,没有任何的处理,直接读

  • 读上来的就是未知字节数的数据,可能是半个报文/一个半/多个
  • 总之它处理不了,只能丢弃,但丢弃了就很大概率会影响之后的处理(因为数据不完整了)
  • 而这样的情况,就叫做数据报粘包问题

就像:

  • 蒸包子/馒头,蒸好后去拿,你本来只想拿一个,但拿起来了一个多/多个/半个

介绍

粘包只是针对用户层的概念

  • 因为传输层面向字节流,对它来说没有报文的概念,自然也就不存在粘包问题

而解决粘包的方法就是制定协议

  • 在之前的网络计算器里就有体现,我们封装了数据长度和特殊字符,使用encode/decode函数做封装和解包

其实不仅只有应用层要解决,下层也需要

  • 因为他们处理数据也得先分出一份完整报文,才能进行封装报头/其他处理
  • 而传递的数据还是以字节为单位

解决的本质

总结一下,解决粘包问题的本质是 -- 在应用层通过协议,明确报文之间的边界

  • 定长报文
  • 使用特殊字符
  • 自描述字段+定长报文 (udp)
  • 自描述字段+特殊字符 (网络计算器,http -- 报头里记录了有效载荷的长度,但报头长度不固定,所以添加特殊字符(空行)作为报头结束的标志)

分离报文后,才进入序列化/反序列化的逻辑

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值