初始TCP三次握手–建立连接
在发送方和接收方方收发TCP数据之前,是需要先建立连接,那么就需要给双方一些信息来确定建立连接。也就是双方问个好,也就是三次握手。
三次握手的过程大概就是:接收方想和发送方通信,那么接收方就会发送一个TCP请求报文过去,这个TCP 的SYN=1,ACK=0,而发送方收到了请求报文后,就会回应一个SYN=1,ACK=1,给接收方,表示发送方愿意和接收方建立连接,当接收方收到了发送方的响应报文后,那么接收方也会给会发送方一个响应报文:SYN=0,ACK=1,表示接收方收到了发送方的响应;
然后发送方就可以开始发送TCP数据包给接收方了。
其实当我们抓包分析过程中,只要:
看到SYN=1,且ACK=0的数据包就是第一次建立连接的包;
看到SYN=1,且ACK=1的数据包就是第二次建立连接的包;
看到SYN=0,且ACK=1的数据包就是第三次建立连接的包(还有可能是释放连接的回应包);
再聊TCP的序号和确认号
TCP的序号表示这一次发送数据过去的的第一个字节大小,TCP的序号也是可以通过上一个回应的TCP包的确认号中知道,因为确认号表示,希望下一次对方给我发送过来的数据从确认号标记的字节开始;
通常确认号可以理解为:收到了前面的确认号个字节-1的数据包,希望对方发送从确认号字节开始数据包过来,那么也就是说确认号还可以通过上一个包的序号+上一个包数据的长度就可以推算出确认号的值了。
我们也知道三次握手是没有数据的,只有TCP的头部字段,所以说对于三次握手的数据包来说,确认号的值,不需要加上数据包的长度,就是可以通过上一个包的序号就可以知道
我们知道客户端和服务器建立连接时候需要三次握手,三次握手中会设置SYN和ACK的值表示第几次的握手情况;
但是我们TCP数据包在建立连接的第一次握手时候,不仅仅发送了SYN=1,ACK=0的字段,还会发送一个字段为序号值过去,也就是序号字段的值,这个值通常是随机值,随机发送过去的!
第一次握手发送过去给对面序号的值:为的是告诉对方,我的序号应该是使用我发送过去的值作为参考计算;
第二次握手也是一样,对方一样不仅发送SYN=1,ACK=1的回应报文,同时也会设置序号为一个随机值,目的也是告诉对方,我的序号从该字节开始计算,以该字节作为参考。
其实我们可以通过抓包工具观察到的
第一次握手的TCP包
第二次握手的TCP包
TCP建立连接–三次握手
TCP三次握手的数据包发送我们已经清楚了,接下来解释一下:客户端和服务器的状态
CLOSED:表示客户端还没开始建立连接;
LISTEN:表示服务器在一直监听客户端发送第一次握手请求过来;
SYN_SENT:表示客户端发送了第一次握手过去给服务器,同时等待服务器发送第二次握手过来;
SYN_RCVD:表示服务器接收到了第一次握手,同时发送第二次握手给客户端,假如再次收到客户端的ACK报文,那么就进入ESTABLISHED状态;
为什么需要三次握手,二次握手为什么不行?
假如第三次握手失败,是如何处理的?
TCP释放连接–四次挥手
当客户端和服务器不再经行通信时候,也就是在建立连接和收发数据的过程都结束后,需要双方断开连接;
断开连接那么需要的步骤是4次挥手,并且,任何一方,无论客户端还是服务器都可以主动提出断开连接;
这里演示的是客户端断开连接;
我们知道,当我方没有数据要继续发送过去,想断开连接的一方都会主动发送一个FIN=1和ACK=1报文过去;
而对方收到后就会回应一个ACK确认报文表示收到了你的断开连接请求;
此时假如对方也表示没有数据要发送给你,所以也会主动发送一个FIN=1,ACK=1的报文过去,表示自己也无数据发了,也想断开连接;那么对方就会回复确认报文ACK发过去;
自此4挥手就结束,TCP连接也就断开了;
为什么断开连接需要4次挥手
我们都知道,断开连接假如只有两次的话,也就是说我给你一次挥手,表示我想和你断开连接,你给我一个回应报文,就表示你知道了和我断开连接,那么就可以正常断开了,为什么不直接两次断开呢?
其实不然,我们没有清楚2次其实不行,所以不清楚一定需要4次,我们要清楚,TCP是全双工模式,也就是说,客户端和服务器可以任何一方发起数据请求和断开,任何一方想发就发;并且第一次挥手和第三次挥手的目的都是不一样的。
当我们清楚挥手的目的后,也就知道了假如只有两次挥手,那么就只有单方面的断开,而对方还是可以给你发送数据,这很明显不是真正的断开连接。
TCP释放连接–状态解读
FIN_WAIT1:表示想主动断开连接;当向对方发送FIN=1,ACK=1报文后,就会进入该状态;
CLOSE-WAIT:表示等待关闭状态;当收到对方的FIN时候,自己会主动回复一个ACK确认报文过去,就会进入该状态;进入该状态也是为了给自己一定的时间思考,是否还有数据要发给对方,假如没有那么也会准备发送FIN=1,ACK=1报文过去。
FIN_WAIT2:只要对方收到ACK报文后,就会自动进入该状态,也是为了等待下一次对方发送过了的FIN=1,ACK=1的报文;
我们的四次挥手也没有标出close状态;
这里的2MSL是一般是4分钟,因为MSL的值TCP规定一般为2分钟;
假如没有TIME_WAIT状态的话,直接进入CLOSE状态,那么很有可能当第四次挥手的ACK确认报文对方没有收到,那么就会让对方一直在干等,假如等不到那么就超时重发第三次握手,多次发送FIN报文过去,浪费资源;
还有一种情况是:一旦发发送了第四次挥手出去,就进入CLOSE状态后,假如刚好客户端开了一个新端口,刚刚和上一次关闭的端口一样,刚好此时的低第次挥手超时没有发送到给对方,那么对方就会重发第三次握手时候,对方刚好发送一个FIN报文过来,凑巧就是新的端口收到了,本来就是向建立连接的,却刚好是关闭了,这就会有bug;
所以说TIME_WAIT的状态很有必要存在;