三十天学不会TCP,UDP/IP网络编程 - RST的用法

不知不觉也写了这么多了,继续个人本身的推广大业~完整版能够去gitbook(https://rogerzhu.gitbooks.io/-tcp-udp-ip/content/)看到。git

若是对和程序员有关的计算机网络知识,和对计算机网络方面的编程有兴趣,虽说如今这种“看不见”的东西真正能在实用中遇到的机会很少,可是我始终以为不管计算机的语言,热点方向怎么变化,做为一个程序员,不少基本的知识都应该有所了解。而当时在网上搜索资料的时候,这方面的资料真的是少的可怜,因此,我有幸前两年接触了这方面的知识,我以为我应该把我知道的记录下来,虽然写的不必定很好,可是但愿能给须要帮助的人多个参考。个人计划是用半年时间来写完这一系列文章,这个标题也是我对太多速成文章的一种态度,好了,废话再也不多扯了,下面是其中的一节内容,更多内容能够去gitbook上找到。程序员

TCP的六个标识符里,有一个表明RST,reset,可是翻译成重置链接彷佛也不太稳当,报告错误也不太合适,做为一个优雅而又逻辑合理的协议,RST对于TCP中出现的错误而致使两端都进入错误处理有重要的做用。面试

状况没有按照预想的进行

有句诗叫作“不如意事常八九,能与人言无二三”,做为一个庞大,复杂,系统的协议,TCP通讯中常常都会出现不是一路顺风的状况。好比前面提过,在三次握手的第二阶段,若是在几回重发都失败的状况下,会回复一个RST包。正是TCP有这个设计才能让TCP称得上连失败了都处理的很优雅。编程

为何要有这么一个RST包而不是在结束的时候直接粗暴的结束或者说啥也不发生的结束呢?仍是先让咱们看看现实中打电话的例子,现实中总有那种妈妈给本身的儿子女儿打电话,儿子女儿不耐烦的,甚至产生冲突。而这个时候若是儿女这一端简单的把电话放下,妈妈那一端就只能听到环境声,对于这边的状况彻底不了解。先不说这种对于对端极不礼貌的作法,至少这样让对端感到很担忧,不知道那一边是怎么状况。而即便你再生气可是你说,不说了,不说了,我挂了,而后挂上电话,哪怕是很重的摔下电话。至少对端能够从嘟嘟声中知道对端已经挂了电话,不用担忧前面描述的那种担忧了。服务器

TCP也是同样,若是没有这个RST包,那么出现出现异常的对端只能等待,由于他根本可能知道对端怎么了。在资源极端重要的网络环境里,这样的作法不只浪费资源更重要的是让TCP这种号称核弹都炸不毁的协议陷入了一种混沌的状态,就像C/C++中的野指针同样,没法管理无序而又混乱。RST包几乎涵盖在TCP每一个状态中,下面在介绍何时会发送RST包以前,先得了解一下正常的状态下的TCP各类状态变迁,这有了解了正常才能更好理解异常嘛。网络

TCP状态变迁图

我一直认为在计算机领域,有两个状态机图最经典,一个是进程调度时候的进程状态变迁图,第二个就是TCP状态变迁图了。这个图清晰的表示了在使用TCP协议通讯时,从创建链接到释放链接的每一个过程,若是你能不靠任何外力的状况下画出这张图,那么不得不说你已经对TCP的每一个阶段了如执掌了,若是再理解下TCP中的流量控制等等,那么其实关于这方面的面试你彻底不用担忧了。tcp

废话很少说了,我从网上挑了一张我以为我看着最舒服的版本:spa

 

这上面的全部状态在前面两节都说过了,除了Established状态,这个状态表示TCP处于链接传输数据的状态,算是一个比较稳定的状态。相比于创建链接和终止链接,这个状态在状态自己上并无什么特别的,就像一条路修完以后,车子就上去跑就好了。可是在链接状态下,TCP的太多设计哲学就蕴含在这里面了,咱们现实中的道路管理要能借鉴里面的一些思想,不少拥堵状况都能避免了。计算机网络

 

言归正传,在这个图中,状态不少,为了演示下怎么样去看这种状态机状态图,我就叙述下怎么样从这个图中找到三次握手中的种种状态变迁。翻译

状态机图主要有两个部分组成,框框表示某种状态,框框之间用线条链接,标识状态的变迁,而在这些线条之上每每会写着一些说明,这些说明被誉为激励条件,一个状态只有通过了某种条件的刺激或者激励才能变迁为另外一个状态。打个比方吧,好比你在发呆,你处于空闲状态,这个时候我打你一下,给你一个刺激,你就会从空闲状态变迁为疼痛状态了。

全部的状态都从Closed开始,在这个图的叙述中,有两条说明,实现表示客户,虚线表示服务器,准确的来讲,这种说法并不严谨,由于在TCP的通讯过程当中其实没有服务器和客户之分,两边都在同等的发送数据。而在这个图或者通常的表述中,主动发起链接的那一方通常会被称之为客户端,被动接受的那一段是服务器端。在了解了这些先决条件以后,那么就来一块儿找找这个图中的三次握手在哪里吧。

首先看Closed状态中的实线,也就是表示客户的状态,在右边,主动发送SYN以后,进入SYN_SENT状态,三次握手第一步完成。而在这以后,收到SYN和ACK包,而后发送ACK以后客户这边就进入了链接状态。

而后再看看另外一条路,从Closed状态虚线进入listen状态,这里不须要任何激励条件就能完成,由于默认服务器一直在监听客户发来的请求,否则那你这个图就画不下去了。在收到SYN,发送SYN和ACK以后进入SYN_RCVD状态,也就是三次握手的第二步。而后就是继续收到对端的ACK以后,进入链接状态。

每一个状态机图都能很方便的变成不少独立的小单元,这也是一个状态机图绘画的好与很差的一个标志。好的状态机图状态之间变迁关系清晰,彼此耦合性很小。而差的你就感受在这种状态变化的指示下只会变成一团混乱。

仔细看一下这个状态机图,你会发现不少前面并无说起的有趣的状态,他们中不少都是很边缘的状况,可是做为一个严谨的协议设计者,应该最大可能留下最小的漏洞。好比图中你会发现从listen状态能够直接变成SYN_SEND状态,回想一下前面说了服务器端会默认为是listen状态从而能够监听对端来的请求。可是若是这个时候服务器端主动发送了SYN,那么他其实就是咱们定义中的“客户”了,因此图中用实线标识这种状况下会SYN_SEND状态。

另一个在发起链接阶段的时候的特殊状况就是SYN_SEND和SYN_RCVD中间那条线,若是一个客户在进入SYN_SEND同时收到对端发送回来的SYN请求,通俗点说就是两端同时发起了链接,两边都是客户了,这个时候TCP不会就此终止,而是进入SYN_RCVD,而后再经历后面的过程以后,两边都进入了Established状态。

这就是这张图的上半部分,若是有兴趣能够看看下半部分整个的关闭流程做为联系。

RST状态变迁图

在了解了正常状态变迁以后,异常状态就不会显得特别的乱了,在网上我找到了这么一张图,我以为画的特别好,就拿来借用了。

 

 

对比上面的图,这张图用红色的部分标识了发送RST的状况,可是也简化了一些上面有的状态变迁,不过这对于了解整个TCP过程当中RST的状态变迁没有那么重要了。

从这个图中第一个能够学到的知识就是经历全部RST状态以后,链接都会进入Closed状态,也就是结束。RST的状态基本分红两种,超时和包丢失。

首先看看超时的状况,在图中就三种包重传超时,SYN,FIN和数据包,能够看到超时都是某种“主动的动做”。好比在三次握手的第二个阶段,重传SYN+ACK一直超时,服务器端就只能发送一个RST到对端了。同理在FIN超时和自己传输数据超时以后,RST也会发送到对方。

第二类是丢失,其实本质上上和上一种状况是一直的,在ACK丢失的状况下,在对端看来就是发送包超时,因此在这种状况下主要是接收RST。

那么在现实生活中,什么样的状况会致使超时呢?其实不少状况均可能发生,好比某一端程序忽然崩溃,某一端忽然没电了等等,这种状况下都会引发超时,从而会致使RST包的发送。若是用官方的语言总结下,RST包会在如下三种状况下被发送:

到达的端口不存在,好比说在客户端发送SYNC想创建链接的时候,对端并无任何监听端口,那么就会发生超时,从而发送RST包。而在UDP这种没有链接的协议中,一个ICMP端口不可达消息就能解决这个问题(若是你对这些名词很陌生,能够看看前面的文章了)。

链接被异常终止, 好比说应用程序崩溃了。

检测半关闭链接,这个半关闭的概念其实在上一篇的时候有所说起,可是不详细,这里正好说明一下。半关闭链接主要发生在某一段已经关闭或者异常终止可是另一段并不知道的状况下。好比在通讯的过程当中,忽然拔掉服务器那边的网线,而后再重启服务器和其应用程序。这个时候链接就处于一个半关闭状态,此时客户机再向对方发一个消息,服务器端会回复一个RST消息,本端就知道刚才发生了什么。

说了这么多,言而总之其实RST主要做用有两个,报告本端异常,告知对方错误,记住这两句话就差很少记住了RST包的做用。

相关文章
相关标签/搜索