文章目录
前言
1. UDP
2. TCP
2.1 TCP 的三次握手
2.2 TCP 四次挥手
2.3 累计确认
2.4 顺序问题和丢包问题
2.5 流量控制的问题
2.6 拥塞控制的问题
总结及面试问题
前言
前端的面试中常常问的 TCP 和 UDP 的区别,网上也有好多内容,好比html
TCP 和 UDP 的区别前端
TCP 是面向链接的,UDP 是面向无链接的
UDP程序结构较简单
TCP 是面向字节流的,UDP 是基于数据报的
TCP 保证数据正确性,UDP 可能丢包
TCP 保证数据顺序,UDP 不保证
以前也由于面试的缘由了解过一下,可是面试官又问了为何 TCP 是可靠传输,一下就露馅了,说不出来了,而后这两天就仔细了解了一下这方面的内容,还专门订阅了极客时间的趣谈网络协议,所以,这篇文章主要基于趣谈网络协议和本身的理解。面试
1. UDP
要想理解 TCP 和 UDP 的区别,首先要明白什么是 TCP,什么是 UDP算法
TCP 和 UDP 是传输层的两个协议缓存
咱们来看一下 UDP 的包头服务器
由上图能够看出,UDP 除了端口号,基本啥都没有了。若是没有这两个端口号,数据就不知道该发给哪一个应用。网络
因此 UDP 就像一个小孩子,特别简单,有以下三个特色数据结构
UDP 的特色tcp
沟通简单,不须要大量的数据结构,处理逻辑和包头字段
轻信他人。它不会创建链接,可是会监听这个地方,谁均可以传给它数据,它也能够传给任何人数据,甚至能够同时传给多我的数据。
愣头青,作事不懂变通。不会根据网络的状况进行拥塞控制,不管是否丢包,它该怎么发仍是怎么发
由于 UDP 是"小孩子",因此处理的是一些没那么难的项目,而且就算失败的也能接收。基于这些特色的话,UDP 可使用在以下场景中post
UDP 的主要应用场景
须要资源少,网络状况稳定的内网,或者对于丢包不敏感的应用,好比 DHCP 就是基于 UDP 协议的。
不须要一对一沟通,创建链接,而是能够广播的应用。由于它不面向链接,因此能够作到一对多,承担广播或者多播的协议。
须要处理速度快,能够容忍丢包,可是即便网络拥塞,也绝不退缩,勇往直前的时候
基于 UDP 的几个例子
直播。直播对实时性的要求比较高,宁肯丢包,也不要卡顿的,因此不少直播应用都基于 UDP 实现了本身的视频传输协议
实时游戏。游戏的特色也是实时性比较高,在这种状况下,采用自定义的可靠的 UDP 协议,自定义重传策略,可以把产生的延迟降到最低,减小网络问题对游戏形成的影响
物联网。一方面,物联网领域中断资源少,极可能知识个很小的嵌入式系统,而维护 TCP 协议的代价太大了;另外一方面,物联网对实时性的要求也特别高。好比 Google 旗下的 Nest 简历 Thread Group,推出了物联网通讯协议 Thread,就是基于 UDP 协议的
还有一些,可是写的太多了也记不住,因此主要记住这几个就够了
2. TCP
首先是 TCP 的包头格式
TCP 的包头有哪些内容,分别有什么用
首先,源端口和目标端口是不可少的。
接下来是包的序号。主要是为了解决乱序问题。不编好号怎么知道哪一个先来,哪一个后到
确认序号。发出去的包应该有确认,这样能知道对方是否收到,若是没收到就应该从新发送,这个解决的是不丢包的问题
状态位。SYN 是发起一个连接,ACK 是回复,RST 是从新链接,FIN 是结束链接。由于 TCP 是面向链接的,所以须要双方维护链接的状态,这些状态位的包会引发双方的状态变动
窗口大小,TCP 要作流量控制,须要通讯双方各声明一个窗口,标识本身当前的处理能力。
经过对 TCP 头的解析,咱们知道要掌握 TCP 协议,应该重点关注如下问题:
顺序问题
丢包问题
链接维护
流量控制
拥塞控制
2.1 TCP 的三次握手
全部的问题,首先都要创建链接,因此首先是链接维护的问题
TCP 的创建链接称为三次握手,能够简单理解为下面这种状况
A:您好,我是 A
B:您好 A,我是 B
A:您好 B
至于为何是三次握手我这里就不细讲了,能够看其余人的博客,总结的话就是通讯双方全都有来有回
对于 A 来讲它发出请求,并收到了 B 的响应,对于 B 来讲它响应了 A 的请求,而且也接收到了响应。
TCP 的三次握手除了创建链接外,主要仍是为了沟通 TCP 包的序号问题。
A 告诉 B,我发起的包的序号是从哪一个号开始的,B 一样也告诉 A,B 发起的 包的序号是从哪一个号开始的。
双方创建链接以后须要共同维护一个状态机,在创建链接的过程当中,双方的状态变化时序图以下所示
这是网上常常见到的一张图,刚开始的时候,客户端和服务器都处于 CLOSED 状态,先是服务端主动监听某个端口,处于 LISTEN 状态。而后客户端主动发起链接 SYN,以后处于 SYN-SENT 状态。服务端接收了发起的链接,返回 SYN,而且 ACK ( 确认 ) 客户端的 SYN,以后处于 SYN-SENT 状态。客户端接收到服务端发送的 SYN 和 ACK 以后,发送 ACK 的 ACK,以后就处于 ESTAVLISHED 状态,由于它一发一收成功了。服务端收到 ACK 的 ACK 以后,也处于 ESTABLISHED 状态,由于它也一发一收了。
2.2 TCP 四次挥手
说完创建链接,再说下断开链接,也被称为四次挥手,能够简单理解以下
A:B 啊,我不想玩了
B:哦,你不想玩了啊,我知道了
这个时候,只是 A 不想玩了,即再也不发送数据,可是 B 可能还有未发送完的数据,因此须要等待 B 也主动关闭。
B:A 啊,好吧,我也不玩了,拜拜
A:好的,拜拜
这样整个链接就关闭了,固然上面只是正常的状态,也有些非正常的状态(好比 A 说完不玩了,直接跑路,B 发起的结束得不到 A 的回答,不知道该怎么办或则 B 直接跑路 A 不知道该怎么办),TCP 协议专门设计了几个状态来处理这些非正常状态
断开的时候,当 A 说不玩了,就进入 FIN_WAIT_1 的状态,B 收到 A 不玩了的消息后,进入 CLOSE_WAIT 的状态。
A 收到 B 说知道了,就进入 FIN_WAIT_2 的状态,若是 B 直接跑路,则 A 永远处与这个状态。TCP 协议里面并无对这个状态的处理,但 Linux 有,能够调整 tcp_fin_timeout 这个参数,设置一个超时时间。
若是 B 没有跑路,A 接收到 B 的不玩了请求以后,从 FIN_WAIT_2 状态结束,按说 A 能够跑路了,可是若是 B 没有接收到 A 跑路的 ACK 呢,就再也接收不到了,因此这时候 A 须要等待一段时间,由于若是 B 没接收到 A 的 ACK 的话会从新发送给 A,因此 A 的等待时间须要足够长。
2.3 累计确认
TCP 如何实现可靠传输?
首先为了保证顺序性,每一个包都有一个 ID。在创建链接的时候会商定起始 ID 是什么,而后按照 ID 一个个发送,为了保证不丢包,须要对发送的包都要进行应答,固然,这个应答不是一个一个来的,而是会应答某个以前的 ID,表示都收到了,这种模式成为累计应答或累计确认。
为了记录全部发送的包和接收的包,TCP 须要发送端和接收端分别来缓存这些记录,发送端的缓存里是按照包的 ID 一个个排列,根据处理的状况分红四个部分
发送而且确认的
发送还没有确认的
没有发送等待发送的
没有发送而且暂时不会发送的
这里的第三部分和第四部分就属于流量控制的内容
在 TCP 里,接收端会给发送端报一个窗口大小,叫 Advertised window。这个窗口应该等于上面的第二部分加上第三部分,超过这个窗口,接收端作不过来,就不能发送了
因而,发送端要保持下面的数据结构
对于接收端来说,它的缓存里面的内容要简单一些
接收而且确认过的
还没接收,可是立刻就能接收的
还没接收,但也没法接收的
对应的数据结构以下
2.4 顺序问题和丢包问题
结合上面的图看,在发送端,一、二、3 已发送并确认;四、五、六、七、八、9 都是发送了还没确认;十、十一、12 是还没发出的;1三、1四、15 是接收方没有空间,不许备发的。
在接收端来看,一、二、三、四、5 是已经完成 ACK 可是还没读取的;六、7 是等待接收的;八、9 是已经接收尚未 ACK 的。
发送端和接收端当前的状态以下:
一、二、3 没有问题,双方达成了一致
四、5 接收方说 ACK 了,可是发送方还没收到
六、七、八、9 确定都发了,可是 八、9 已经到了,六、7 没到,出现了乱序,缓存着可是没办法 ACK。
根据这个例子能够知道顺序问题和丢包问题都有可能存在,因此咱们先来看确认与重传机制。
假设 4 的确认收到了,5 的 ACK 丢了,六、7 的数据包丢了,该怎么办?
一种方法是超时重试,即对每个发送了可是没有 ACK 的包设定一个定时器,超过了必定的事件就从新尝试。这个时间必须大于往返时间,但也不宜过长,不然超时时间变长,访问就变慢了。
若是过一段时间,五、六、7 都超时了就会从新发送。接收方发现 5 原来接收过,因而丢弃 5;6 收到了,发送 ACK,要求下一个是 7,7 不幸又丢了。当 7 再次超时的时候,TCP 的策略是超时间隔加倍。每当遇到一次超时重传的时候,都会讲下一次超时时间间隔设为先前值的两倍。
超时重传的机制是超时周期可能相对较长,是否有更快的方式呢?
有一个快速重传的机制,即当接收方接收到一个序号大于指望的报文段时,就检测到了数据流之间的间隔,因而发送三个冗余的 ACK,客户端接收到以后,知道数据报丢失,因而重传丢失的报文段。
例如,接收方发现 六、八、9 都接收了,可是 7 没来,因此确定丢了,因而发送三个 6 的 ACK,要求下一个是 7。客户端接收到 3 个,就会发现 7 的确又丢了,不等超时,立刻重发。
2.5 流量控制的问题
在流量控制的机制里面,在对于包的确认中,会携带一个窗口的大小
简单的说一下就是接收端在发送 ACK 的时候会带上缓冲区的窗口大小,可是通常在窗口达到必定大小才会更新窗口,由于每次都更新的话,刚空下来就又被填满了
2.6 拥塞控制的问题
也是经过窗口的大小来控制的,可是检测网络满不尽是个挺难的事情,因此 TCP 发送包常常被比喻成往谁管理灌水,因此拥塞控制就是在不堵塞,不丢包的状况下尽量的发挥带宽。
水管有粗细,网络有带宽,即每秒钟能发送多少数据;水管有长度,端到端有时延。理想状态下,水管里面的水 = 水管粗细 * 水管长度。对于网络上,通道的容量 = 带宽 * 往返时延。
若是咱们设置发送窗口,使得发送但未确认的包为通道的容量,就能撑满整个管道。
如图所示,假设往返时间为 8 秒,去 4 秒,回 4 秒,每秒发送一个包,已通过去了 8 秒,则 8 个包都发出去了,其中前四个已经到达接收端,可是 ACK 还没返回,不能算发送成功,5-8 后四个包还在路上,还没被接收,这个时候,管道正好撑满,在发送端,已发送未确认的 8 个包,正好等于带宽,也即每秒发送一个包,也即每秒发送一个包,乘以来回时间 8 秒。
若是在这个基础上调大窗口,使得单位时间能够发送更多的包,那么会出现接收端处理不过来,多出来的包会被丢弃,这个时候,咱们能够增长一个缓存,可是缓存里面的包 4 秒内确定达不到接收端课,它的缺点会增长时延,若是时延达到必定程度就会超时重传
TCP 拥塞控制主要来避免两种现象,包丢失和超时重传,一旦出现了这些现象说明发送的太快了,要慢一点。
具体的方法就是发送端慢启动,好比倒水,刚开始倒的很慢,渐渐变快。而后设置一个阈值,当超过这个值的时候就要慢下来
慢下来仍是在增加,这时候就可能水满则溢,出现拥塞,须要下降倒水的速度,等水慢慢渗下去。
拥塞的一种表现是丢包,须要超时重传,这个时候,采用快速重传算法,将当前速度变为一半。因此速度仍是在比较高的值,也没有一晚上回到解放前。
总结及面试问题
TCP 和 UDP 的区别
TCP 是面向链接的,UDP 是面向无链接的
UDP程序结构较简单
TCP 是面向字节流的,UDP 是基于数据报的
TCP 保证数据正确性,UDP 可能丢包
TCP 保证数据顺序,UDP 不保证
什么是面向链接,什么是面向无链接
在互通以前,面向链接的协议会先创建链接,如 TCP 有三次握手,而 UDP 不会
TCP 为何是可靠链接
经过 TCP 链接传输的数据无差错,不丢失,不重复,且按顺序到达。TCP 报文头里面的序号能使 TCP 的数据按序到达报文头里面的确认序号能保证不丢包,累计确认及超时重传机制TCP 拥有流量控制及拥塞控制的机制