我不懂微服务:TCP三次握手

Posted 杨友山

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我不懂微服务:TCP三次握手相关的知识,希望对你有一定的参考价值。

一、关于TCP
TCP是一种网络传输协议,这个协议只有资深网络工程是才能描述清楚,其他人的描述都是片面的。博主也试图从自己认识的角度讲解。
先来看看OSI七层模型,这个模型很多很都认识。如图,

这个图我们暂时不用深入理解,我们抓住这三点就好了:
1、网络之间的连接其本质是一个点到另一个点建立连接;
2、单纯的一个点建立连接,只有计算机自己认识,大规模建立网络门槛比较高,因为需要懂计算机原始连接的人才行。为了让网络给人们造福,需要在这种连接的基础上层层封装,每一层封装网络连接的本质没变,但是操作起来更方便。
3、数据从应用层发下来,会在每一层都会加上头部信息,进行封装,然后再发送到数据接收端。接收端接收到数据后按照从外层到内层反解封。
每一层大概完成的事情,如下:
应用层——用户A编辑邮件内容发送给用户B,B实现存储。
内容+目标。

表示层——客户端A格式→网络通用的标准数据格式→客户端B格式。
统一数据格式。

会话层——规定何时建立连接,何时发送数据。
怎么连接,怎么传输。

传输层——建立连接,断开连接。有确认功能,如果信息传输不完整,会重发。
提供正确的、可靠的传输处理。

网络层——真正的传输数据,将邮件从主机A发送到主机B。
把全部数据发送给目标地址。

数据链路层——通过传输介质互联的设备之间进行数据处理。负责物理层面互联的、节点之间的通信传输,发送一个分段内的数据。

数据帧的生成与接收。

物理层——负责0、1比特流(0、1序列)与高低电压、光的闪灭之间的互换。


TCP就在传输层,它的格式数据格式如下,

1、Source Port和Destination Port:分别占用16位,表示源端口号和目的端口号;用于区别主机中的不同进程,而IP地址是用来区分不同的主机的,源端口号和目的端口号配合上IP首部中的源IP地址和目的IP地址就能唯一的确定一个TCP连接;
2、Sequence Number:用来标识从TCP发端向TCP收端发送的数据字节流,它表示在这个报文段中的的第一个数据字节在数据流中的序号;主要用来解决网络包乱序的问题;
3、Acknowledgment Number:32位确认序列号包含发送确认的一端所期望收到的下一个序号,因此,确认序号应当是上次已成功收到数据字节序号加1。不过,只有当标志位中的ACK标志为1时该确认序列号的字段才有效。主要用来解决不丢包的问题;
4、Offset:给出首部中32 bit字的数目,需要这个值是因为任选字段的长度是可变的。这个字段占4bit(最多能表示15个32bit的的字,即4*15=60个字节的首部长度),因此TCP最多有60字节的首部。然而,没有任选字段,正常的长度是20字节;
5、TCP Flags:TCP首部中有6个标志比特,它们中的多个可同时被设置为1,主要是用于操控TCP的状态机的,依次为URG,ACK,PSH,RST,SYN,FIN。每个标志位的意思如下:
URG:此标志表示TCP包的紧急指针域(后面马上就要说到)有效,用来保证TCP连接不被中断,并且督促中间层设备要尽快处理这些数据;
 ACK:此标志表示应答域有效,就是说前面所说的TCP应答号将会包含在TCP数据包中;有两个取值:0和1,为1的时候表示应答域有效,反之为0;
 PSH:这个标志位表示Push操作。所谓Push操作就是指在数据包到达接收端以后,立即传送给应用程序,而不是在缓冲区中排队;
 RST:这个标志表示连接复位请求。用来复位那些产生错误的连接,也被用来拒绝错误和非法的数据包;
 SYN:表示同步序号,用来建立连接。SYN标志位和ACK标志位搭配使用,当连接请求的时候,SYN=1,ACK=0;连接被响应的时候,SYN=1,ACK=1;这个标志的数据包经常被用来进行端口扫描。扫描者发送一个只有SYN的数据包,如果对方主机响应了一个数据包回来 ,就表明这台主机存在这个端口;但是由于这种扫描方式只是进行TCP三次握手的第一次握手,因此这种扫描的成功表示被扫描的机器不很安全,一台安全的主机将会强制要求一个连接严格的进行TCP的三次握手;
 FIN: 表示发送端已经达到数据末尾,也就是说双方的数据传送完成,没有数据可以传送了,发送FIN标志位的TCP数据包后,连接将被断开。这个标志的数据包也经常被用于进行端口扫描

Window:占2个字节。窗口值作为接收方让发送方设置其发送窗口的依据。
CheckSum:占2字节。检验和字段检验的范围包括首部和数据这两部分。和UDP数据报一样,在计算检验和时,也要在TCP报文段的前面加上12字节的伪首部。伪首部的格式与UDP用户数据报的伪首部一样,但要将伪首部第四个字段中的17 改为6(协议号),把第5字段中的UDP长度改为TCP长度。
Urgent Pointer:占2字节。紧急指针仅在URG=1时才有意义,它指出本报文段中的紧急数据的字节数。

TCP Options(variable length,optional) 选项和填充数据
以上为消息头,
剩余则是本次传输的数据。

上图解释成中文,是这样:

二、三次握手
通过TCP连接,无论哪一方向另一方发送数据之前,都必须先在双方之间建立一条连接。在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。三次握手的目的是同步连接双方的序列号和确认号并交换 TCP窗口大小信息。 

三次握手之后,双方开始传数据。

整个流程如下:
1、客户端和服务端最初都为CLOSED状态。客户端主动打开,发送连接请求报文段,将SYN标识位置为1(TCP规定SYN=1时不能携带数据),Sequence Number置为a(a为随机值),然后客户端状态变为:CLOSED=>SYN_SEND状态;

2、服务器收到SYN报文段进行确认,将SYN标识位置为1,ACK置为1,Sequence Number置为b,Acknowledgment Number置为a+1,然后服务端状态变为:CLOSED=>SYN_RECV状态。客户端接收到服务端信息后状态变为:SYN_SEND=>ESTAB_LISHED;
3、客户端再进行一次确认,将ACK置为1(此时不用SYN),Sequence Number置为a+1,Acknowledgment Number置为b
+1发向服务器,服务端状态变为:SYN_RECV=>ESTAB_LISHED状态。

其本质是双方依次向对发一个数字Sequence Number并让对方返回一个确认数字Acknowledgment Number。如果对方返回的确认数字符合我的预期,表示安全,可以建立连接了。

比如,客户端和服务端通讯类似这个场景。

客户端和服务端是俩死党,他俩约定为了防止聊天聊错了对象,聊天前需要确认下信息,对下黑话。
比如定了一个暗号,谁要说话就带了一个数字A,你下次也要发给我确认这个数字,规律是这个数字默认+1。
于是,某一天下午,
客户端和服务端都在午睡,
客户端做了噩梦,自己醒了,想找服务端唠唠家常......
  客户端:服务端你好,咱俩唠唠吧(SYNC变为1了),9527
  服务端:没问题(给客户端一个确认信息了ACK=1),666,9528(确认数字),咱开始聊吧(SYNC=1)
  客户端:好吧开始聊(给服务端也回一个确认信息ACK=1,这时就不用说咱开始聊吧所以不用再传SYNC=1了)。9528,667(确认数字)

  客户端/服务端: 晚上咱去喝点?(这就开始传数据了)

三、为什么三次握手

三次握手,主要解决:为了防止已失效的连接请求报文段突然又传送到了服务端。
如果取消第三次握手,那么只要服务器确认后就开始建立连接。假如有一个客户端请求由于某种原因延迟了很久才到达服务端,而此时客户端并没有发起建立连接。
但是服务端确认了,然后服务端发起建立连接。这样服务端一直等待客户端连接(实际上客户端不会发起),造成资源浪费。

以上是关于我不懂微服务:TCP三次握手的主要内容,如果未能解决你的问题,请参考以下文章

我不懂微服务:http服务

我不懂微服务:http服务

TCP三次握手wireshark抓包分析

TCP三次握手及TCP连接状态 TCP报文首部格式

TCP/IP之TCP协议首部三次握手四次挥手FSM

实例解释三次握手发生了什么