文章目录
- 三次握手
- 四次挥手
- 为什么要进行三次握手?
- 三次握手也不安全
本篇解析的主要是TCP的三次握手和四次挥手的过程
三次握手
如图所示,在TCP要进行链接的时候,其实是要进行三次握手的
第一次握手是指,此时客户端要给服务器发送一个SYN的标记位,服务器收到这个标记位后,回返回客户端一个SYN和ACK,表示的是对于上一个报文的确认,同时SYN也表示服务端允许和客户端建立链接,那么接下来客户端继续给服务器发送ACK进行确认,此时就建立好了三次握手的过程
在建立好握手之后,之后进行数据传输的时候就只需要传一个数据,应答一次,传一个数据,应答一次
如何理解connect和accept呢?
在进行网络套接字的过程中,使用TCP协议就用过这两个函数,在客户端向服务端建立链接的时候,首先要调用connect来建立链接的请求,本质上就是会要求客户端构建一个SYN报文推送给服务端,那最终是否会成功呢?就会看的是connect的返回值
connect函数只是负责发起三次握手,至于对于三次握手的细节并不过多参与,这个握手的过程是由操作系统自主完成的,至于其中内部的细节,可以理解为在调用了connect之后,就进入了阻塞的状态,只有在我握手完成后才会返回establish,表示的是返回
第二个函数是accept,它叫做是获取链接,这个函数本身不参与三次握手,它只会把获取好的链接直接拿上来,如果底层没有建立好的链接,那么这个函数就会一直阻塞住,因此我们说,当通信的双方在经过三次握手之后,对应的操作系统的链接状态就会发生变化,这个就叫做是同步发送
此时如果要是服务端收到了一个SYN,那么就表示要进行同步,所以就会返回一个ACK的报文,只要收到了这个ACK的报文,对应的客户端就会再发出去一个ACK的报文,随之就会把状态更换为establish,表示已经建设完毕了,对于服务端来讲,只有第三个报文回来了,它才能进行establish,换句话说,双方建立establish的时间是有一定的时间差的,而同时客户端和服务端双方在进行三次握手期间对应的连接状态是会发生变化的,而这个状态的变化都是由操作系统本身来进行自主维护的
理解write和read
那之后再对于数据通信的时候,就涉及到了read和write的问题,如果read当中没有数据,那么就默认进行阻塞,本质上就是缓冲区当中没有数据
接下来就是最后一个状态,断开连接的状态
四次挥手
如果客户端和服务器此时已经建立好了链接,但是现在要进行断开连接了,那么该如何进行呢?
首先在要进行断开连接的时候,对应的应用层就要进行的是进程退出,具体的可以使用的是在上层调用对应的close来关闭链接,所以会在网络中发送一个FIN的报文,表示的是要进行断开连接了
但是TCP协议当中可以看出,建立链接必定是一方主动一方被动,然后进行三次握手,建立成功,那么反之对于断开连接呢?客户端说我要和你断开连接,就可以真的断开了吗?如果服务端还有信息要进行传递呢?所以在断开连接这个过程中,需要服务端也发送一个FIN的报文,表示我也没有什么要给你发送了,此时就发送一个FIN的报文,表示要和客户端断开连接了
TCP的通信是基于链接的,也就是说在TCP建立通信之前就要确认好链接,在断开连接之后此时也是需要进行四次挥手的,这都体现来了TCP的通信要给予链接
为什么要进行三次握手?
这个问题看似简单,实际上背后可描述的内容还是比较多的
在TCP进行建立链接的时候,真的是三次握手吗?其实这三次握手是算上捎带应答才是三次握手,同样的道理,在进行四次挥手的时候也是有捎带应答,才能被压缩为是四次挥手,本质上这种三次握手和四次挥手都是体现了这种一来一回的可靠性,将来如果要是进行发送消息,一端发消息一端收消息,本质上至少可靠的要给对方发送一次消息,对于客户端和服务端都是如此,两个方向的应答都要可靠,这个道理是比较朴素的
这里我再给出一个对应的理由:
1. 验证全双工
当客户端要给服务端发送一个报文的时候,无论是客户端还是服务端,在双方进行通信之前,都至少要保证进行过一次收和发的工作,由于是三次握手,所以能够可靠的保证客户端和服务端至少进行过一次收和发,这样的就代表的是,验证了通路是否顺畅,换句话说就是验证全双工
建立链接的本质,就是要测试网络状态是否适合通信,所以在双方进行三次握手的时候,就要保证通信的双方都能进行收合法的工作,否则就不能保证基于TCP协议的全双工来进行通信了
那此时可能会出现的问题是,两次握手难道不可以吗?问题在于,此时对于客户端来讲,两次握手确实可以保证它发了一个报文,收了一个报文,但是对于服务端来讲,只能验证它可以收报文,但是至于它发出去的报文对方能不能收到,这是无法进行保证的,所以说两次握手是不能保证全双工的
如果是一次握手呢?那就更不能验证了,所以最少是要进行三次握手,验证全双工
2. 奇数次握手,可以保证一般情况下握手失败的连接成本是嫁接在client端的
如果现在是一次握手,我们画出下面这张图:
如果客户端给服务端发送了一个SYN请求,那么服务端就会认为此时链接已经建立好了,那么服务端就会对应的创建维护链接的结构体,而创建链接的结构体是有成本的,换句话说就是会占据对应的内存资源,对应维护的这个链接,不管怎么样都会占据在这里消耗内存,那么假设服务端收到了大量的SYN请求,那么就会建立大量的没用的结构体对象,那么很容易就会出现内存被充满的情况
随之而来的就是可能会出现被攻击的现象,一次握手这样的场景有明显的逻辑漏洞,因此是不能被采纳的
为什么不是四次握手,五次握手甚至更多呢?
经过前面的验证,其实三次握手是验证全双工的最小次数,在验证可以了之后就不必进行额外的验证了,过多的验证反而会建立额外的链接,增加更多的成本
三次握手也不安全
即便是三次握手,也可能会出现漏洞,下面给出一个可能的例子
假设现在有一个服务器,如果存在恶意分子把一批特定群体的客户端,在他们内部植入对应的病毒信息,这些病毒就要求它们要在特定的时间向一个服务器发送请求,即便是正常的三次握手,也可能会把服务器的链接资源消耗结束,这种情况就叫做是肉机,问题就相当于TCP可以解决这样的问题吗?答案是不能的,TCP的三次握手只能保证在逻辑上没有出现明显的漏洞,而实际上也依然会存在一些问题,所以才会产生了有对应的网络安全的公司有防火墙这样的策略等等