互联网协议学习日记

一:何为互联网协议

程序员最关注的也就是应用层,在应用层中程序员可以自定义协议,设计应用协议就是约定前后端的交互接口,写程序的时候,会涉及到前端和后端进行通信,那么我们就需要约定好前端发出什么样的请求,后端就需要返回啥样的数据,在http协议中就用到了Ajax和form标签,这两个都很重要,是前后端产生联系的接口。

二:设计应用层协议

​ 1、考虑清楚客服端和服务器之间要传递那些信息 (需求而定)
​ 2、确定好信息之后,需要明确协议格式 (最好用已经发明好的协议模板往上面套)
三:协议传输

3.1、UDP协议格式

1、端口号取值范围:
    > 0~65535  -----> 64k
    > 这里的64k在互联网程序中数据是非常小的,解决办法:1、手动对应用层进行拆分;2、直接使用TCP协议
校验和:
1、是用来验证数据是否正确的一种手段。
2、但在网络传输的过程中,受于自然干扰,导致可能会破坏原有要传输的数据信息 (光/电信号,太阳黑子/太阳风暴…),这样导致其中的bit发生改变(比特翻转),那为了检验出数据是不是有误,可以结束校验和来检查。
3、也有解决办法就是用ECCC内存,这个内存能够对bit翻转进行应对,一般用在服务器上,个体用就ECCC内存就太贵了。

​ 4、校验和既验证数据个数,也验证数据内容。

如果最后结果是相同的,数据就没有发生变化;输入的数据相同,算法相同 ,得到的校验和结果也就相同;输入的数据不同,算法相同,得到的校验和结果大概是不同的。

校验和可以通过第三方工具进行计算,不需要自己手动的计算。

3.2 TCP协议
这里重点介绍TCP协议特性中的 可靠传输。

TCP的核心就是解决“可靠传输”问题,而我们的UDP是无可靠传输,(可以简单的理解TCP最后快递是否寄到目的地,我们是知道结果的,反而UDP在寄快递的时候,快递丢没丢失,是否到达目的地我们是不知道的)TCP会反映结果,UDP是不会反应结果。

TCP的可靠也不是说数据100%被对方收到,而是发的数据,对方收没收到数据,是会感知到的。

发送方又是如何知道接收方,到底是否收到数据尼???

3.2.1、确认应答
​ 当发送一条消息的时候,对方是会回复的。这样看似没有问题,但是这种确认机制,存在一个很大的问题,连续发消息会发生上什么??

正常的逻辑是会已上图所示,但是网络上传输的数据顺序性是不能保证的,可能也是后发先置的情况。

网络上的传输是复杂的 ,可能在回复第一条消息的时候进行了堵塞,延迟,导致第二条消息先送达,就会影响我们的正确理解。为了解决这样的问题,就引入了一个重要的概念“序号”

加上编号之后,就不会影响理解正确的意思了;在编号中带上的编号,称为“序号”,应答文中的编号,称之为“确认序号”,他两之间存在对应的关系。

确认序号表示,该序号之前的数据会被收到了,可以直接从1001序号开始发送数据。

有了确认应答,就更好的保证了TCP的可靠性,可以让发送方清楚的知道,对方是否收到,但是万一有某个数据丢了,还是要想办法处理一下的。

 

3.2.2、超时重传
当发送的一条消息对方没有回复,可能出现两种情况:

1、我这边发的信息,直接发丢了;

2、对方看到了我的信息,给我回复信息的时候,信息丢了。

这两种情况,我们是区分不了的,既然区分不了,那就认为是我方的过错,等10分钟(超时),如果我放还是没收到对方的信息,那么我就重新再发一次!这就是所谓的“重传”。

此时这种情况对方就收到了两次一模一样的信息,对于人来说,这样的数据重复,是没有影响的,但是对于计算机来说,就会出现问题,例如发的是一个转账请求,如果产生超时重传,这不得发两次转账😫😫😫(达咩)。

但在TCP中也是会自动去重的功能,发送过去的数据,先放到接收方的内核中的缓冲区(是以阻塞队列数据结构实现的),每一段消息的都带有序号,如果新来的一个消息序号和之前缓冲区中的序号重复了,TCP直接就会进行去重操作。

应用程序从接受缓冲区中去数据的时候,可能不是一个重复的数据,调用 socket api 得到的数据,也是不重复的!

如果重传的数据也丢失了尼!!!😤😤😤

那么TCP有做了对应的处理:

1、重传不会无休止的进行,重传一定的次数,就会放弃重传,认为连接不可恢复,断开TCP连接。

2、重传的时间间隔,是不相同的,每次重传的时间间隔都会变长,再次丢失数据,那么认为恢复的概率就很小。

发生了两次数据丢包,意味着大概率的情况下,当前的网络丢包率非常高,可能网络遇到了严重的故障。

TCP在进行上诉的确认应答和超时重传机制上,可靠性就得到了良好的保证

这里下面就是面试的八股文了。都很重要的

3.2.3、连接管理
这里的连接管理,是讨论TCP是如何建立连接的,TCP又是如何断开连接的。

这里就涉及到了TCP是经过三次握手建立连接,四次挥手断开连接。

3.2.3.1 建立连接(三次握手)
TCP协议格式有6个特殊位:


 

这里的六个比特位,在TCP中是特殊的六个标志位:

1、ACK:acknowledge(挥手) ,当这一位 为 1 时,表示当前发送的数据,“确认报文段”就表示是对刚才收到数据的应答。

确认应答机制中的“应答报文”同样也是ACK这一位为1.

2、SYN:synchronize(同步),当这一位为1时,表示当前发送的这个请求,是“同步报文段”,是要和对方建立连接。

3、FIN:结束报文段

A想和B建立连接(客服端主动发起):

1、SYN发送想和对方建立连接的请求;

2、B收到了A的SYN做出了应答ACK;

建立连接是需要“双向奔赴”的

3、B也发送SYN请求想和对方建立连接;

4、A收到了请求做出了ACK回应;

这是建立连接的整个过程,但是我们可以简化,把2,3给合并起来,就形成了三次握手。

ACK和SYN都是内核自己触发的,属于同一个时机。

❓❓❓ 为啥中间要合并???

1、分两次发送效率太低了;

2、分两条发,需要正对两条数据,分别进行封装和分用,实际上这两条数据刚好可以合并,也就合并了。

❔❔❔ TCP已经有了确认应答和超时重传保证了可靠性,为啥还要三次握手?握手有什么用?

1、三次握手其实是一个前提条件,先确认当前网络环境是否具备连接,进行可靠的传输。

2、同时也能协商一些重要的参数(通信双方是需要一些共同参数进行配合的)

如果网络不通畅,大概率的出现丢包和重传

三次握手进一步验证,通信的双方发送能力和接收能力是否都是正常 的。

这也是保证TCP可靠传输的机制,但他是一个前提条件。

3.2.3.2 断开连接(四次挥手)
断开连接也是双向远离的过程,主要是通过 FIN这一个特殊位。

通信的双方各自向对方发送 FIN(结束报文),再各自返回ACK响应。

这里中间一般是不能合并到一起的,但是在特殊情况之下是可以合并

触发FIN 的情况:

1、手动调用 socket.close()

2、强制退出进程

当客户端触发FIN之后,服务器只要收到FIN,就会立即返回ACK(内核完成);当服务器的代码中运行到 socket.close()操作的时候,就会触发FIN。

这是两个不同的时机,中间带有一定的时间间隔

CLOSE_WAIT && TIME_WAIT:

在TCP中会向多线程一样有多种状态,但是我们重点关注 CLOSE_WAIT and TIME_WAIT这两个状态。

 

CLOSE_WAIT
1、如果服务器那边没有调用close方法,此时就会看到 CLOSE_WAIT的状态(如上图的右边是服务器,左边是客服端)。

2、如果服务器那边看到了 lots of CLOSE_WAIT,就说明服务器出现了BUG,就是代码写的有问题。

TIME_WAIT
1、谁主动断开连接,谁进入 TIME_WAIT 状态

建立连接,一定是客户端主动发起;

断开连接,可能是客服端,也可能是服务器主动发起断开

2、TIME_WAIT会脱离进程的存在,即使进程结束,TIME_WAIT状态可能仍然存在,存在的目的就是为了处理最后一个ACK丢包之后重传的问题。

所以最后在客服端回复完最后ACK的时候,别先释放,先等一段时间,确保FIN不被重传了,就可以真正释放连接了。

TIME_WAIT等待的时间,叫做 2MSL (MSL是网络上两点之间传输消耗最大的时间,此处的MSL的值是可以配置的)。

TCP的可靠性已经得到了保障,但是TCP在可靠性的基础上,提高效率。

3.2.4、滑动窗口
滑动窗口是提高TCP传输效率的重要方法。

要知道客服端每次给服务器发送SYN,都要等待服务器返回ACK,等待时间就会让速度效率就会减慢,滑动窗口就是减少无效的等待次数,提高速度效率。

我们就通过一次性发一批SYN的操作,然后等一批ACK的操作,这样一份时间等待多组ACK提高了速度效率。

等待的过程中ACK也不会同时到达,是有先有后的,假如2001先应答,那么在12000的数据就被对方已经收到了,接下来A就可以立即发出500160000。

这里一次发送长度为 N 的数据,然后等一批ACK,那么这个N就成为“窗口的大小”。

N越大,传输的速率也就越快,但是N是有界限的,不能无限大。

所谓“滑动”又是什么意思???

由图可以看出,当主句A接受到ACK的时候,那么窗口就会往后滑动,等待数据的范围也就会变化,这种显现称之为“滑动”。

虽然 滑动窗口 减少了等待次数,提升了效率,但是仍然无法跟UDP无确认应答的速度相比。

传输数据大多数都会有丢包的情况,既然滑动窗口是一批一批的操作,如果放中间数据丢包了咋整???

1、如果是ACK丢包,影响是不大的。

这张图可以看出,中间多次ACK丢包,但是我们TCP是有确认序号 概念的,当1001ACK丢了,但是后面6001这个ACK送到了,说明6001之前的数据也就顺利是被收到了,这个丢包关系就不大了。

2、如果是SYN丢包了,那么是会出发重传的机制的

由图可以看出,SYN发的1001~2000 这一段的数据丢包了,这个主机A一直连续发很多的数据,但是主句B一直想主句A索要 1001 这一段的数据,那么主句A收到3次同样的确认应答都是1001,那么主句A就意识到,1001这个包的数据丢失了,触发重传机制,主句B得到了缺的1001这个数据,就会把这个数据补上了,直接返回7001就行了,因为A一直发数据的,B都把这些数据记录在接受缓冲区中,当缺的补上了,就发现接受缓冲区里面7001之前的数据都齐,于是直接ACK7001.

这些都是用到了确认序号 和 超时重传 重要机制,

3.2.5、流量控制(安全机制)
也是一种保证可靠性的机制

之前也说了,虽然滑动窗口的“窗口”越大,传输效率就越快,但是并不是无限放大的,就越好,如果说发送方发的太快,接受方顶不住,其余额外的数据也是大概率会丢包的,丢包就触发超时重传,我们要找到合适的发送速率和接受处理速率相匹配才行。

流量控制就是根据接收方处理数据的能力,来制约发送方的滑动窗口大小

所以说发送方的滑动窗口大小是变化,不固定的。

衡量接收方的处理速率,处理的速率取决于应用程序,调用socket api 的读取操作(read)数据的速度。

在更详细的的衡量处理速率,那么通过接收缓冲区中剩余空间的大小,来衡量。结社接收缓冲区一共是4k,当前使用3k还剩1k,此时接收方返回ACK的时候,告诉发送方,我们缓冲区还剩1k的空间了,你们悠着点,接下来,发送方就可以按照1k这样的窗口来发数据。

conclusion:通过接收缓冲区剩余的空间大小来衡量发送窗口的大小。

何为接收缓冲区:
每个主机上都会有用户态和内核态,发送数据的时候,都是内核态之间建立TCP连接(三次握手,四次挥手)发送数据,完了之后,都是用户态去取内核态的数据;接收缓冲区就在内核态中,这个接收缓冲区使用阻塞队列实现的,数据都放到了缓冲区中,代用 socket api来读取其中的数据,只要应用程序读了数据,此时接收缓冲区中对应的数据就可以被删除掉。
1何为接收缓冲区:
2每个主机上都会有用户态和内核态,发送数据的时候,都是内核态之间建立TCP连接(三次握手,四次挥手)发送数据,完了之后,都是用户态去取内核态的数据;接收缓冲区就在内核态中,这个接收缓冲区使用阻塞队列实现的,数据都放到了缓冲区中,代用 socket api来读取其中的数据,只要应用程序读了数据,此时接收缓冲区中对应的数据就可以被删除掉。

具体关于socket api的调用,网络编程可以看 网络初始&网络编程 这篇文章。

极端情况:

接收方的接收缓冲区满了,窗口大小为0,这时先让发送方暂停不要发送数据,接收方没有收到发送的数据,那么就不会返回ACK。但是当接收缓冲区已经腾出空间了,没有返回ACK,说明发送方就不能及时感知到。

怎么解决?

为了让发送方及时感知到,窗口已有剩余,发送方就会定时给接收方放送一个“探测报文”,这个探测报文不传输实际的数据,只是为了触发ACK,只是为了更新,接收方的窗口大小。

3.2.6、拥塞控制
它也是可靠性的机制

拥塞控制是根据发送方到接收方这一系列通信链路的处理速率来衡量的。

在主机A和主机B之间网络通信这个过程会经过很多的设备,各式各样的路由器,交换机…,这些设备是为了转发数据的,传输的数据一方面会受到中间节点的处理能力的影响,另一方面会受到主机B之间的处理能力影响。

由于整个链路中的每个节点的情况是非常复杂的,如果中间某个链路节点出现问题,就不能快速的转发了,我们只需要把整个链路看做一个整体即可,然后通过“实验”的方式,不断的尝试不同的窗口大小,保证可靠性的前提下,获取合适的窗口大小。

拥塞控制会设置出一个“拥塞窗口”这样的指标,通过拥塞窗口来影响到滑动窗口的窗口大小。


 

这个图反应了“拥塞窗口”变化规律:

1、刚开始传输的时候,慢开始;

2、指数规律增长,短时间内窗口大小加速提升;

3、指数增长到一定数值的时候(超过设定的國值),进入线性增长;

4、遇到了网络拥塞,丢包,立即让窗口大小回到最初很小的值,同时修改线性增长的國值,为刚才窗口大小的一半。

5、继续重复刚才的步骤。
 

3.2.7、延时应答
考虑在可靠性的前提下,尽量把这个窗口大小给变大一些

当A给B传数据的时候,会把数据放入B的接收缓冲区中,B也不停的在接收缓冲区中取数据,B接收到A的SYN不要立即返回ACK,等一个500ms,B就会从接收缓冲区中取出一部分的数据,接收缓冲区就空出来了一定的空间,这时再次发出ACK,那么ACK的报头返回的接收缓冲区就会比立即发出的接收缓冲区更大,那么SYN传输的窗口大小也会更大。

窗口越大,网络吞吐量就越大,传输效率就越高。我们的目标是在保证网络不拥塞的情况
下尽量提高传输效率

TCP的延时应答,能够让程序对于接收方的处理能力有一个更准确的评估。(关联了接收缓冲区剩余空间的大小,同时也关联了程序的处理速度)。

延迟的范围:

1、数量的限制:每隔N个包就应答一次;

2、时间限制:超过最大延迟时间就应答一次;(延时的最大时间是不会超过超时重传)

3.2.8、捎带应答
客服端和服务器之间的通信模型是“一问一答”,客户端发一个请求,服务器返回一个响应,但是HTTP也是基于TCP,客户端发送一个请求,服务器也会回一个ACK,然后在根据请求构造计算响应,再把响应返回给客户端。

这样一来服务器返回的ACK和响应就不在同一时间了,就不会合并成同一个数据报。

但是TCP中有延时应答的机制,B给A返回的ACK不会立即返回,而是等一会在返回,就导致发送时间可能和响应时间是同一时机,是同一时机就可以合并。

这种情况就是 捎带应答,也是延时应答的延伸。

有了捎带应答,四次挥手,可能就变成三次挥手了,

 

触发捎带应答不是100%触发,主要看写的代码。假设代码中的延时应答时间是200ms,在这200ms之内,代码就得执行到close。

3.2.9、粘包问题
不算是TCP的机制,是应用层都会有粘包问题;

粘包问题指多个TCP数据包到达的时候,如果不显示约定包和包之间的边间,容易产生混淆。

 

由图可看,接收缓存区里面有一串数据,但并不能区分是那一段跟那一段的数据,这种粘包粘的是应用层的数据报,只要有一个能区分数据报与报之间的边界就行了,如在应用层的数据 333 出现一个分号333;那么我们就用这个 分号 来区分边界,这种也是应用层协议设定的。

在HTTP协议中(应用层协议)我们发送 GET 请求,一般GET请求是没有bady,空bady后面还有一个\n换行,那么这个换行就是区分边界的标志符;

在POST请求中,带bady,我们还是要找到POST的\n,这\n之间在找到 Content-Length这么长的数据,那么这么长的数据也就达到了请求边界。 可以看看 HTTP 协议 中的 GET和POST协议格式。

总结,解决粘包问题两种典型方案:

1、通过分隔符指定

2、通过长度来指定

3.2.2.10 异常机制
建立好连接的双方,在通信工程中,遇到了一些突发状况,如何处理?

1、进程终止:A B 中的某个进程突然终止,但是操作系统会早做准备,操作系统会释放这个进程的相关资源(TCP这里依赖一个socket文件,操作系统会自动关闭这个socekt文件,类似于scocket.close())触发四次挥手。

2、机器重启或关机:这个还是交给操作系统先把所有应用程序强制终止,一终止进程就和前面进程终止触发四次挥手一样。

3、机器掉电/网线断开:

这种直接掉电的才是让操作系统猝不及防,特别是服务器会对机器本身制造伤害(主要是硬盘),因此服务器的机房,应该准备备用电源UPS,这样断电了,还可以用UPS撑一段时间,保证服务器的这些机器通过合法程序关机。

两个主机通信,如果是接收方掉电,那么就不会返回ACK,发送方就超时重传,重传一定次数,尝试重新连接,最后认为连接不可恢复,放弃连接,释送发送方这边自己保存的连接信息。

如果是发送方掉电,在TCP协议中连接的双方都会给彼此发送“探测报文”,“探测报文”不传递实际的数据,这是用来检查对方是否可以正常工作。

有个心跳包的机制,很多程序中都会用到心跳包的机制。

总结:

TCP可靠性:确认应答,超时重传,连接管理,流量控制,拥塞控制,心跳机制

TCP效率:滑动窗口,延时应答,捎带应答

编码注意事项:粘包问题

TCP的原则:优先保证可靠性,在可靠性的基础上,进一步提升效率;

关于TCP和UDP的优势:TCP可靠性;UDP效率更高

场景中,对可靠性要求不高的,同时对效率要求比较高的,优先考虑UDP。

场景中,需要可靠传输,必优先考虑TCP。



经典面试题:

如何基于UDP实现可靠传输??

看似问UDP,实则答TCP,把TCP中的可靠机制,搬给UDP即可。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值