TCP提供的可靠传输机制/原理,浅谈TCP和UDP的区别

TCP和UDP的区别:

  1. UDP是无连接,不可靠的,效率更高;TCP是有连接,可靠传输,效率相对于UDP更差
  2. UDP是面向数据报(一次发,一次收);TCP是面向字节流(多次发,多次收)
  3. UDP有接收缓冲区,没有发送区;TCP两者都有
  4. UDP数据大小受限,TCP大小不限
  5. TCP提供了很多可靠的传输机制

TCP可靠性的机制

确认应答
超时重发
连接管理
这三个我的前一篇文章提到了,这里就不再赘述了
https://blog.csdn.net/weixin_45070922/article/details/117253531?spm=1001.2014.3001.5501
流量控制
这里流量控制是接收端的事情,但是作用于发送端;
TCP支持根据接收端的处理能力, 来决定发送端的发送速度. 这个机制就叫做流量控制;
接收端处理能力有限,位避免发送的太快,处理不过来,接收端主动告诉发送端,少发一点,间接eider控制发送端滑动窗口大小(发送数据大小)
在这里插入图片描述
接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段, 通过ACK端通知发送端;
窗口大小字段越大, 说明网络的吞吐量越高;
接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值通知给发送端;发送端接受到这个窗口之后, 就会减慢自己的发送速度;
如果接收端缓冲区满了, 就会将窗口置为0; 这时发送方不再发送数据, 但是需要定期发送一个窗口探测数据段, 使接收端把窗口大小告诉发送端.

拥塞控制

发送端在不了解网络状态的情况下,采用慢启动机制,先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输数据;

此处引入一个概念程为拥塞窗口
发送开始的时候, 定义拥塞窗口大小为1;
每次收到一个ACK应答, 拥塞窗口加1;
每次发送数据包的时候, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较小的值作为实际发送的窗口;
在这里插入图片描述
此处引入一个叫做慢启动的阈值
当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增长
当TCP开始启动的时候, 慢启动阈值等于窗口最大值;
在每次超时重发的时候, 慢启动阈值会变成原来的一半, 同时拥塞窗口置回1;

TCP提高性能的机制

滑动窗口
网络数据传输,如果使用串行的方式,发送端和接收端,都有发送/接收数据的操作,但是本身的执行时间很快的,但是数据在网络中传输时,可能比较慢。
为了解决这一问题:引入滑动窗口,同时发送多个数据报,同时接收多个响应的ack,进而提高效率
发送时:下一个是多少,是取连续的序号最大值+1,也代表之前的数据都已经收到了
在这里插入图片描述

窗口大小指的是无需等待确认应答而可以继续发送数据的最大值. 上图的窗口大小就是4000个字节(四个段)
窗口大小 = min(流量窗口大小,拥塞窗口大小)
窗口的滑动:发送后没有返回ack的数据,都保存在发送缓冲区,接收到下一个是多少的ack之后,可以计算出可以滑动的大小(下一个是多少 减去 窗口中的最小序号)

两中丢包
返回的ack丢了
在这里插入图片描述
传输过去的数据报丢了
在这里插入图片描述
当某一段报文段丢失之后, 发送端会一直收到 1001 这样的ACK, 就像是在提醒发送端 “我想要的是 1001” 一样;
如果发送端主机连续三次收到了同样一个 “1001” 这样的应答, 就会将对应的数据 1001 - 2000 重新发送(快重传);
这个时候接收端收到了 1001 之后, 再次返回的ACK就是7001了(因为2001 - 7000)接收端其实之前就已经收到了, 被放到了接收端操作系统内核的接收缓冲区中;

延迟应答
拿上应答,返回的流量窗口大小会比较小,接收端处理速度是比较快的,稍等一段时间,接收端消费一些接收缓冲区数据后,再返回的流量窗口会更大,发送端设置的滑动大小就可能更大,网络数据传输的吞吐量就更高。

假设接收端缓冲区为1M. 一次收到了500K的数据; 如果立刻应答, 返回的窗口就是500K; 但实际上可能处理端处理的速度很快, 10ms之内就把500K数据从缓冲区消费掉了;
在这种情况下, 接收端处理还远没有达到自己的极限, 即使窗口再放大一些, 也能处理过来;如果接收端稍微等一会再应答, 比如等待200ms再应答, 那么这个时候返回的窗口大小就是1M;

捎带应答
不管那一端(客户端还是服务端),需要主动发送数据报,可以和接收数据报后返回的ack数据报,合并为一个,这里就有点类似于TCP三次握手中,第二次合并syn和ack的数据报

粘包问题

产生的原因:
首先要明确, 粘包问题中的 “包” , 是指的应用层的数据包.
在TCP的协议头中, 没有如同UDP一样的 “报文长度” 这样的字段, 但是有一个序号这样的字段. 站在传输层的角度, TCP是一个一个报文过来的. 按照序号排好序放在缓冲区中.
站在应用层的角度, 看到的只是一串连续的字节数据.
那么应用程序看到了这么一连串的字节数据, 就不知道从哪个部分开始到哪个部分, 是一个完整的应用层数据包.
解决方法:
对于定长的包, 保证每次都按固定大小读取即可; 例如上面的Request结构, 是固定大小的, 那么就从缓冲区从头开始按sizeof(Request)依次读取即可;
对于变长的包, 可以在包头的位置, 约定一个包总长度的字段, 从而就知道了包的结束位置; 对于变长的包, 还可以在包和包之间使用明确的分隔符(应用层协议, 是程序猿自己来定的, 只要保证分隔符不和正文冲突即可);

扩展问题

基于传输层UDP协议,如何传输超过64K的数据?
基于传输层UDP协议,如何保证可靠传输?
:在应用层实现类似TCP所有可靠传输的机制

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值