TCP三次握手详解
1. 定义:传输控制协议-----TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。
- 字节流:消息是「没有边界」的,所以无论我们消息有多大都可以进行传输。并且消息是「有序的」,当「前一个」消息没有收到的时候,即使它先收到了后面的字节,那么也不能扔给应用层去处理,同时对「重复」的报文会自动丢弃。
- 面向连接:一定是「一对一」才能连接,不能像 UDP 协议可以一个主机同时向多个主机发送消息,也就是一对多是无法做到的;
- 可靠的:无论的网络链路中出现了怎样的链路变化,TCP 都可以保证一个报文一定能够到达接收端;
2.报文格式
- 端口号:用来标识同一台计算机的不同的应用进程。 TCP报头中的源端口号和目的端口号同IP数据报中的源IP与目的IP唯一确定一条TCP连接
1)源端口:源端口和IP地址的作用是标识报文的返回地址。
2)目的端口:端口指明接收方计算机上的应用程序接口。
- 序列号和确认号:是TCP可靠传输的关键部分。序列号是本报文段发送的数据组的第一个字节的序号。在TCP传送的流中,每一个字节一个序号。
e.g: 一个报文段的序号为300,此报文段数据部分共有100字节,则下一个报文段的序号为400。所以序号确保了TCP传输的有序性。确认号,即ACK,指明下一个期待收到的字节序号,表明该序号之前的所有数据已经正确无误的收到。确认号只有当ACK标志为1时才有效。比如建立连接时,SYN报文的ACK标志位为0。
- 首部长度:4bits。由于首部可能含有可选项内容,因此TCP报头的长度是不确定的,报头不包含任何任选字段则长度为20字节,4位首部长度字段所能表示的最大值为1111,转化为10进制为15,15*32/8 = 60,故报头最大长度为60字节。首部长度也叫数据偏移,是因为首部长度实际上指示了数据区在报文段中的起始偏移值。
- 保留:为将来定义新的用途保留,现在一般置0。
- 控制位:URG ACK PSH RST SYN FIN,共6个,每一个标志位表示一个控制功能。
1)URG:紧急指针标志,为1时表示紧急指针有效,为0则忽略紧急指针。
2)ACK:确认序号标志,为1时表示确认号有效,为0表示报文中不含确认信息,忽略确认号字段。
3)PSH:push标志,为1表示是带有push标志的数据,指示接收方在接收到该报文段以后,应尽快将这个报文段交给应用程序,而不是在缓冲区排队。
4)RST:重置连接标志,用于重置由于主机崩溃或其他原因而出现错误的连接。或者用于拒绝非法的报文段和拒绝连接请求。
5)SYN:同步序号,用于建立连接过程,在连接请求中,SYN=1和ACK=0表示该数据段没有使用捎带的确认域,而连接应答捎带一个确认,即SYN=1和ACK=1。
6)FIN:finish标志,用于释放连接,为1时表示发送方已经没有数据发送了,即关闭本方数据流。
- 窗口:滑动窗口大小,用来告知发送端接受端的缓存大小,以此控制发送端发送数据的速率,从而达到流量控制。窗口大小时一个16bit字段,因而窗口大小最大为65535。
- 校验和:奇偶校验,此校验和是对整个的 TCP 报文段,包括 TCP 头部和 TCP 数据,以 16 位字进行计算所得。由发送端计算和存储,并由接收端进行验证。
- 紧急指针:只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。 TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。
- 选项和填充:最常见的可选字段是最长报文大小,又称为MSS(Maximum Segment Size),每个连接方通常都在通信的第一个报文段(为建立连接而设置SYN标志为1的那个段)中指明这个选项,它表示本端所能接受的最大报文段的长度。选项长度不一定是32位的整数倍,所以要加填充位,即在这个字段中加入额外的零,以保证TCP头是32的整数倍。
- MSS:最大传输段 MSS=MTU-IP头部-TCP头部 1500-20-20=1460(最大) MTU :最大传输单元 ————默认1500字节
- 数据部分: TCP 报文段中的部分是可选的。在一个连接建立和一个连接终止时,双方交换的报文段仅有 TCP 首部。如果一方没有数据要发送,也使用没有任何数据的首部来确认收到的数据。在处理超时的许多情况中,也会发送不带任何数据的报文段。
3.可靠性
- 确认机制:对每次接收到的数据段,都需要进行一次确认回复。
- 重传机制:当一个数据段中某一个报文丢失后,会要求重新传输这个丢失的报文
- 排序机制:当一个数据段被分为多个数据包时,从不同路径传输,最终到达目的地 的顺序会被打乱,所以需要重新进行排序。
- 流控机制(滑动窗口机制):通过调节窗口大小来对流量大小进行控制
4.wireshark抓包分析
-
第一次握手
-
第二次握手
-
第三次握手
5.三次握手
1.TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态;
2.TCP客户进程也是先创建传输控制块TCB,然后向服务器发出连接请求报文,这是报文首部中的同部位SYN=1,同时选择一个初始序列号 seq=x ,此时,TCP客户端进程进入了 SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号。
3.TCP服务器收到请求报文后,如果同意连接,则发出确认报文。确认报文中应该 ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己初始化一个序列号 seq=y,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号 。
4.TCP客户进程收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号。
5.当服务器收到客户端的确认后也进入已建立连接状态,此后双方就可以开始通信了。
6.为什么要握手三次?
客户端和服务端要确认彼此都有收发的能力。
- 第一次握手:客户端发出连接请求,服务端收到连接请求,至此,服务端知道客户端有发送能力。
- 第二次握手:服务端收到第一次客户端发出的连接请求后,向其发出收到连接请求的响应和连接请求,至此,客户端知道服务端有发送能力和接收能力。
- 第三次握手:客户端收到服务端对它第一次所请求的回应后,发送收到连接请求的响应,服务端收到后,至此,服务端知道客户端有接收能力。
- 服务端和客户端都知道彼此有收发能力后,才可建立连接。从底层来说,三次握手的关键是要确认对方收到了自己的数据包,这个目标就是通过“确认号(Ack)”字段实现的。计算机会记录下自己发送的数据包序号 Seq,待收到对方的数据包后,检测“确认号(Ack)”字段,看Ack = Seq + 1是否成立,如果成立说明对方正确收到了自己的数据包。所以,至少要三次才能建立连接。
防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
- 已经失效的客户端发出的请求信息,由于某种原因传输到了服务器端,服务器端以为是客户端发出的有效请求,接收后产生错误。
防止服务器端开启一些无用的连接增加服务器开销
- 第一次握手客户端发送的TCP报文,服务端成功接收;然后第二次握手,服务端返回一个确认收到消息的TCP报文,但这个报文因为某些原因丢失了,那么客户端就一直收不到这个TCP报文。客户端设置了一个超时时间,超过了就重新发送一个TCP连接请求,那么如果没有第三次握手的话,服务端是不知道客户端是否收到服务返回的信息的,这样没有给服务器端一个创建还是关闭连接端口的请求,服务器端的端口就一直开着,等到客户端因超时重新发出请求时,服务器就会重新开启一个端口连接。那么服务器端上没有接收到请求数据的上一个端口就一直开着,长此以往,这样的端口多了,就会造成服务器端开销的严重浪费。
7.:TCP的三次握手都可以携带数据吗?如果不是,那么哪一次握手可以携带数据,其他的为啥不能携带数据?
- 假设第一次握手客户端携带数据到服务器,服务器解析并存储此次连接的信息,如果数据量大,服务端就要分配足够的内存来进行存储,假如有黑客while(1000000000)来新建连接,结果可想而知,服务器将会被占用大量的内存。第三次握手,此时对于客户端来说,连接已经建立,客户端携带数据则完全没有问题。
8.传输的过程中,报文是否会丢失?
- 第一次握手报文丢失
客户端发送 SYN 报文,然后进入到 SYN_SENT 状态。
客户端迟迟收不到服务端的 SYN-ACK 报文,就会触发客户端的超时重传机制。
在 Linux 里,客户端的 SYN 报文最大重传次数由/proc/sys/net/ipv4/tcp_syn_retries内核参数控制,这个参数是可以自定义的,默认值一般是 5。每次超时的时间是上一次的 2 倍。当第五次超时重传后,会继续等待 32 秒,如果服务端仍然没有回应 ACK,客户端就不再发送 SYN 包,然后断开 TCP 连接。
- 第二次握手报文丢失
第二次握手时,服务端会进入 SYN_RCVD 状态
客户端:第一次握手发出去的报文没有得到回复,那么客户端就会觉得自己的 SYN 报文丢失,于是客户端就会触发超时重传机制,重传 SYN 报文。
服务端:发送SYN_ACK报文后将会开启一个定时器,如果报文没有得到回应,就会触发超时重传机制,重传 SYN-ACK 报文,重传的次数由/proc/sys/net/ipv4/tcp_synack_retries控制,默认是5次。
- 第三次握手报文丢失
服务端:发送SYN_ACK报文后将会开启一个定时器,如果超过了定时器设置的时间都没有收到客户端的ACK,将会重发SYN_ACK包。由/proc/sys/net/ipv4/tcp_synack_retries控制,默认是5次。
客户端:现在是 ACK 报文,拥有独特的权限,所以不会重传。