1. TCP协议
1.1 TCP数据包头
要了解三次握手和四次挥手,首先需要了解下TCP数据包头的结构,如下:
- 源端口、目的端口:16位长,标识出远端和本地的端口号;
- 序号:SEQ,32位长,标识发送的数据包的顺序,防止数据包乱序;
- 确认号:32位长,接收方对发送方发送来的TCP报文段的响应,其值是对收到的报文序号加1,用于解决不丢包的问题;
- TCP头长:4位头长,标识tcp头部可以有多少个32bit,即多少个4字节,因为头长是4位,最大能表示15,所以TCP头部最大就是15*4等于60个字节,也就是说TCP包头最长可以有60个字节;
- URG:表示紧急指针是否有效;
- ACK:ACK位置1表明确认号是合法的,如果ACK为0,那么数据包不包含确认信息,确认字段被省略;
- PSH:提示接收端应用程序应该立即从TCP接收缓冲区中读走数据,为接收后续数据腾出空间;
- RST:表示要求对方重新建立连接,用于复位由于主机崩溃或其他原因而出现的错误的连接,还可以用于拒绝非法的数据报或拒绝连接请求;
- SYN:表示请求建立连接;
- FIN:表示通知对方要关闭连接了;
- 窗口大小:16位长,是一种流量控制的手段,这个窗口,指的是接收通告窗口,它告诉对端本端的TCP缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度;
- 校验和:16位长,由发送端填充,接收端根据该值,校验接收到的TCP报文段在传输过程中是否损坏,校验包括头部和数据部分,它是TCP可靠传输的一个重要保障;
- 紧急指针:16位长,是一个正的偏移量,它和序号相加表示最后一个紧急数据的下一个字节的序号,确切的说,它是紧急指针相对当前序号的偏移,是发送端向接收端发送紧急数据的办法;
- 可选项:TCP头部最长可以有60个字节,而前部分已知的字段占用了20个字节,所以选项最多可以有40个字节,包括最大TCP载荷,窗口比例、选择重复数据报等选项;
注意:TCP数据包是没有IP地址的,只有端口
1.2 三次握手协议
在利用TCP实现源主机和目的主机通信时,目的主机必须同意,否则TCP连接无法建立。为了确保TCP连接的成功建立,TCP采用了一种称为三次握手的方式,三次握手方式使得“序号/确认号”系统能够正常工作,从而使它们的序号达成同步。如果三次握手成功,则连接建立成功,可以开始传送数据信息。 三次握手:为应用程序提供可靠的通信连接,适合于一次传输大批数据的情况,并适用于要求得到响应的应用程序。 其三次握手分别为:
- 源主机A的TCP向主机B发送连接请求报文段,其首部中的SYN(同步)标志位应置为1,表示想跟目标主机B建立连接,进行通信,并发送一个同步序列号X(例:SEQ=100)进行同步,表明在后面传送数据时的第一个数据字节的序号为X 1(即101), 此时client端状态为SYN_SENT。
- 目标主机B的TCP收到连接请求报文段后,如同意,则发回确认。再确认报中应将ACK位置为1.确认号为X 1,同时又向A也发送一个SYN=1,并发送一个序号Y, 此时server端状态为SYN_RCVD。
- 源主机A的TCP收到目标主机B的确认后要想目标主机B给出确认。其ACK置为1,确认号为Y 1,而自己的序号为X 1。TCP的标准规定,SYN置1的报文段要消耗掉一个序号, 当两边都确认完成后,状态改为ESTABLISHED。
运行客户进程的源主机A的TCP通知上层应用进程,连接已经建立。 当源主机A向目标主机B发送第一个数据报文段时,其序号仍为X 1,因为前一个确认报文段并不消耗序号。 当运行服务进程的目标主机B的TCP收到源主机A的确认后,也通知其上层应用进程,连接已经建立。至此建立了一个全双工的连接。
1.3 tcp断开连接四次挥手
tcp建立连接是三次,但断开连接却要四次,是因为tcp是全双工的,两个方向上都需要进行关闭。
- 当主机A完成数据传输后,将控制位FIN置1,向主机B提出停止TCP连接的请求,状态改为FINWAIT1,此时,该数据包中,序列号为主机B发送的上一个数据包中的确认号值,而确认号为主机A发送的上一个数据包中的序列号 该数据包所带的数据的大小;
- 主机B收到FIN后对其作出响应,确认这一方向上的TCP连接将关闭,将ACK置1,此时服务器状态改为CLOSEWAIT, 客户端状态改为FINWAIT_1,此时序列号为上一步中的确认号,确认号为上一步中的序列号加1;
- 由B 端再提出反方向的关闭请求,将FIN置1,服务端状态为LASTACK,客户端状态为TIMEWAIT,此时序列号为上一步的确认号,确认号为上一步的序列号加上数据包所带数据的大小;
- 主机A对主机B的请求进行确认,将ACK置1,双方向的关闭结束状态为CLOSED,此时序列号为上一步中的确认号,确认号为上一步中的序列号加1;
注意 : FIN和SYN一样,也要消耗一个序号。理论上服务器在TCP连接关闭时发送的终止数据包中,只有终止位置是1,然后客户端进行确认。但是在实际的 TCP实现中,在终止数据包中,确认位和终止位是同时置为1的,确认位置为1表示对最后一次传输的数据进行确认,终止位置为1表示关闭该方向的TCP连 接。
1.4 TCP有哪些状态
一般我们可以使用netstat查看当前socket状态。
- CLOSED:表示初始状态;
- LISTEN:表示服务器端的某个socket处于监听状态,可以接受连接;
- SYNSENT:三次握手时,客户端发送第一次SYN连接请求后,状态SYNSENT;
- SYN_RCVD:也是三次握手时服务端的一个中间状态;
- ESTABLISHED:表示连接已经建立,这里要说明一下,其实TCP连接并不是真的有什么东西连着在,只是说双方都是ESTABLLISHED状态,就说明双方连接正常;
- FINWAIT1:已经建立连接后,其中一方请求终止连接,四次挥手中间状态;
- TIME_WAIT:表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL(默认是2min)后回到CLOSED可用状态;
- CLOSING:表示发送FIN报文后,没有收到对方的ACK报文,反而收到了对方的FIN报文,这种情况其实就是双方同时关闭socket;
- CLOSE_WAIT:四次挥手中间状态,表示在等待关闭连接;
- LAST_ACK:四次挥手时被动关闭一方在发送FIN报文后,等待对方的ACK确认报文;
- RST:同时打开和同时关闭;
1.5 TIME_WAIT为什么要等2MSL才会变为CLOSED
有两个原因:
- 可靠地终止TCP连接,在四次挥手的最后一步中,可能客户端发送到服务端的确认包丢失,服务端就会重发结束报文段,客户端重新发起确认报文段,而这就需要停留一段时间;
- 保证让迟来的TCP报文段有足够的时间被识别并丢弃,如果没有停留一段时间,原来客户端的端口号就可以立即被另外一个应用程序重用,此时如果服务端有迟来的报文段,就会发到该新的应用程序上去,而这显然是不被允许的;
注意:报文段的生存周期是一个MSL,所以在2MSL后,不会还存在迟到的报文段。