TCP首部格式
要解析TCP报文,首先要了解它的首部格式:
TCP协议的可靠性就体现在首部的序号和确认序号。可以保证数据的按序到达,和数据丢包后的重传机制。
(1)序号:TCP是面向字节流的,在一个TCP连接中传送的字节流中的每一个字节都按顺序编号,整个要传送的字节流的起始序号必须在建立连接时设置。假设某一报文段的序号字段值为301,而数据长度为100字节,那么下一个报文应该从401开始。
(2)确认序号:是指该序号之前的所有序号都收到了,若数据在传送过程中丢失,那么可以马上重传丢失的报文信息。对于上面的例子,如果序号字段为301的报文在传送过程中被丢失,并且301之前的报文都已经安全到达,那么对方的确认字段中就会是301,表明之前发送的301号报文没有接收到,需要重传。
就是因为有序号和确认序号,所以TCP协议是非常可靠的。
(3)数据偏移:该字段将TCP报文的首部与有效载荷区分了。因为TCP首部中存在选项字段,而选项字段的长度是可变的,所以不能用固定值来区分。
(4)6个标志位
URG:紧急,当URG=1时,表明紧急指针字段有效。它告诉操作系统当前报文中有紧急数据,需要优先处理。所以TCP就会把该紧急数据插入到本报文段数据的最前面,而在紧急数据之后仍是普通数据。
ACK:确认,仅当ACK=1时,确认号字段才有效,所以ACK基本上都是1。
PSH:推送,当两个应用进程进行交互式的通信时,有时在一段的应用进程希望在键入一个命令后立即就能够收到对方的响应。在这种情况下,TCP就可以使用推送操作。当发送方把PSH置1,并立即创建一个报文发送出去,接收方TCP收到PSH=1的报文段,就尽快的交付接受应用进程,而不用再等到整个缓存都填满了才向上交付。
RST:复位,当RST=1时,表明TCP连接中出现严重差错,必须释放连接,然后再重新建立连接。RST置1用来拒绝一个非法的报文段或一个非法的连接。
SYN:同步,在连接建立时用来同步序号。当SYN=1且ACK=0时,表明这是一个连接请求报文段。对方若同意建立连接,则应在响应报文段中使SYN=1且ACK=1。因此,SYN置1就表示这是一个连接请求或连接响应报文段。
FIN:终止,当FIN=1时,表明此报文段的发送方的数据已经发送完毕,并要求释放运输连接。
(5)窗口:指发送本报文段的一方的接收窗口(而不是自己的发送窗口),表明接收方目前允许对方发送的数据量。是为了平衡发送与接收速度的。不至于一方过快,而另一方跟不上的情况。
(6)检验和:检验数据在发送过程中有没有丢失一部分数据。
URG与PSH的区别
URG与PSH都是让TCP优先处理该段报文,那么它们有什么区别呢?
URG是紧急指针,它是直接交付给进程而不进入缓冲区,进程只需处理紧急数据,其他普通数据仍需在缓冲区内等待。
而PSH是将数据放入缓冲区,不用等待缓冲区被写满,可以立即交付,但进程处理的是当前缓冲区内的全部数据。
TCP三次握手
(1)客户端首先主动打开连接,然后发出连接请求SYN=1,序号是1000,数据长度为0,最大段尺寸mss是1460,如果一个段太大,封装成帧后超过了链路层的最大帧长度,就必须在IP层分片,为了避免分片,客户端声明自己的最大段尺寸,建议服务器端发来的段不要超过这个长度。
(2)服务器端发送连接确认报文,SYN=1,ACK=1,序号是8000,确认序号是1001,表明1001之前的报文均已收到,下次请发送序号为1001的报文,并且客户端的最大段尺寸为1024。
(3)客户端发送连接确认报文,确认收到了客户端的连接确认报文,此时双方都知道连接已经建立完成,确认序号是8001。
那么对于TCP的三次握手为什么是三次握手,而不是两次握手呢?
假设是两次握手:
客户端收到了服务器的连接响应报文后,认为此时连接已经建立。但是服务器并不知道客户端有没有收到报文,那么服务器会一直发送连接响应报文,而客户端一直不回应服务器的报文,服务器就会一直发送……最后造成资源浪费。
可有可能在服务器端发送连接响应报文后,客户端并没有收到,但服务器端并不知道,服务器端正常发送数据,但客户端一直没有接受,服务器就一直发送数据……最后也会造成资源浪费,并且客户端并没有接收到数据。
所以TCP的连接只能是三次握手,双方都确认收到了对方的连接相应报文,建立连接。
TCP四次挥手
(1)首先客户端主动关闭连接,然后发送关闭连接请求报文FIN=1,ACK=1,序号为1021,数据长度为0(因为没有发送数据),确认序号为8011。此时客户端进入终止等待1状态。等待服务器释放链接。
(2)客户端收到报文后,发送响应报文,确认序号为1022。同时客户端会通知上层的应用进程,释放从客户端暗道服务器方向的连接。
【注:】此时客户端关闭了连接,客户端不能发送数据给服务器,但服务器仍可以发送数据给客户端。
(3)客户端收到服务器的响应报文后,进入终止等待2状态,等待服务器主动发送关闭连接请求报文。
(4)服务器发送关闭连接请求报文,FIN=1,ACK=1,序号为8011,确认序号为1022。此时服务器进入最后确认状态,等待客户端的响应报文。
(5)客户端收到服务器的关闭连接请求报文后,发送关闭连接响应报文,同时客户端进入时间等待状态,等待2MSL(最长报文段寿命)后,客户端认为连接已经关闭。
(6)服务器收到客户端发送的关闭连接响应报文后,关闭连接。
至此客户端与服务器均已关闭连接。
那么,在客户端发送完关闭连接响应报文后,为什么要等待2MSL?
其一,为了保证客户端发送的最后一个响应报文能够到达服务器。这个响应报文有可能丢失,因而使处在最后等待状态的服务器收不到对己发送的响应报文。服务器会超时重传关闭连接请求报文,而客户端就能在2MSL时间内收到该重传的报文,接着客户端重新发送一次关闭连接响应报文,并且重新启动2MSL计时器。那么客户端和服务器都会进入关闭连接状态;但如果客户端在发送完关闭连接响应报文后立即进入关闭连接状态,那么当服务器超时重传关闭连接请求报文后,客户端就无法接受该报文,那么也无法响应,最后客户端将无法进入关闭连接状态。
其二,防止上一节的“已失效的连接请求报文段”出现在本连接中。客户端在发送完关闭连接响应报文后,再经过2MSL时间后,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。
那么,TCP可以是3次挥手吗?
例如:这样可以吗?
假设有这样一种情况,客户端按发送关闭连接请求报文给服务器,但服务器还想发送数据给客户端,此时连接还没有关闭,服务器可以发送数据,那么此时客户端并不知道服务器是否收到了自己发送的连接关闭请求报文,客户端可能会重新发送请求报文,也可能会一直等待服务器的响应,服务器可能接收到了,也可能没有接收到,那么就不能正常关闭连接了。