一、先来说一下什么是TCP/IP?
TCP/IP(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP协议不仅仅指的是TCP 和IP两个协议,而是指一个由FTP、SMTP、TCP、UDP、IP等协议构成的协议簇, 只是因为在TCP/IP协议中TCP协议和IP协议最具代表性,所以被称为TCP/IP协议。(来源于百度百科)
二、三次挥手
过程
第一次握手:
客户端将标志位SYN(同步位)设置为1,用来表示要发起一个连接,然后再随机的产生一个seq=x,这个seq就是表示一个随机数,然后客户端将这个数据包发送给服务器端,发送后,客户端的状态更改为:SYN_SENT,这个状态表示请求连接,也就是客户端发送连接请求后,正在等待服务器端回复时的状态。
第二次握手:
服务器端接收到了数据包,发现里面有个SYN=1,就明白了是客户端发起了连接请求,这个时候服务器端就要对客户端进行回应,表示我同意(或不同意)你发过来的请求,回应的内容就是:同步标志位SYN=1,确定标志位ACK=1,还有一个确定号ack=x+1,(就是表示我收到了你发送的X,我现在希望能收到x+1,大概就是这个道理),并且再给客户端发送一个随机数seq=y(这个就和第一次握手客户端给服务器端发送seq=x是一个道理).然后将这个数据包发送给客户端。然后服务器端进入SYN_RCVD状态。
第三次握手:
客户端收到确认后,要去检查ack是否是x+1,ACK是否是1,如果这两个值是正确的,那么客户端再给服务器端发送一个数据包:ACK=1,ack=y+1,然后服务器收到后,就明白了我们都能收到对方的信号,然后就可以进行数据传输了。
三、四次挥手
挥手就是数据传输完了,我要和你段开这个连接时的过程。
过程:
第一次挥手:
客户端发起一个FIN=1,seq=m给客户端用来表示我希望断开连接了,然后进入FIN_WAIT1状态,也就是客户端不会再发送数据了,
第二次挥手:
服务器端收到FIN后,知道客户端想断开服务器,然后就客户端再发送一段报文,ACK=1,seq=n,ack=m+1,也就是服务端告诉客户端,我收到你想要断开这个请求了,此时服务端并没有自己发送FIN结束标志,也就是说,服务器端可能还有数据没发送完或者需要处理,但是服务端知道客户端要断开,服务端先告诉客户端,我收到你要断开这个请求了。然后服务端进入CLOSE_WAIT状态,客户端收到后进入FIN_WAIT2状态,
第三次握手:
服务器端发送一个FIN=1,ACK=1,ack=m+1,seq=q,这个就是服务端给客户端发送了断开请求。服务端进入LAST_ACK状态。
第四次握手:
客户端收到服务端的FIN后,进入TIME_WAIT状态,然后给服务端发送一个ACK=1,ack=q+1,seq=m+1,客户端收到后,进入CLOSED状态。至此,完成四次握手,中断请求。
注:客户端与服务端:谁发起了请求谁就是客户端,TCP传输是双向的,两端均可以作为客户端或服务端。
四、常见问题
1、为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?
因为在连接请求中,服务端可以将ACK确认标志与SYN同步标志放在一个报文中发送,
而在关闭连接的过程中,服务端收到FIN结束标志后,这只表示客户端没有数据向服务端发送了,但是服务端可能还有数据要想客户端发送,所以还不能立即关闭连接,所以服务端收到客户端发送的结束请求后,需要先给客户端发送一个ACK确认标志,告诉客户端,我收到你的关闭请求了,你先等我一下,让我先处理完事情再关闭。如果不告诉客户端,客户端就会重复向服务端发送结束请求。然后等待服务端处理完后,服务端再给客户端发送一个FIN结束标志,表示我也搞完了,我们可以都可以关闭请求了。所以一般在关闭连接时,ACK报文和FIN报文是分开发送的。
2、为什么需要三次握手?而不是两次?
TCP传输是双向的,要保证双方都能发送和接收。所以客户端给服务端说我能给你发,然后服务端给客户端说我能收到你的,我也能给你发,第三次客户端要告诉服务端,你发的我收到了,保证服务端到客户端发送数据是畅通的。这个答案是有点片面的。
个人理解:
在传输过程中,客户端和服务端并不是特指哪一方,而是谁发起请求谁就是客户端,也就是说“握手”的目的就是客户端要向服务端发送数据,而达到这个目的需要经过三次协商才能保证数据传输的可靠性。姑且理解为,客户端向服务端单向传输数据,需要三次相互间的通信协商才能保证客户端数据可靠的传输到服务端。
TCP可靠传输是依靠seq序列号来达成的,如果是二次握手,客户端发起的请求连接,在半路上因为网络延迟等原因滞留了,直到连接请求已经释放了服务端才收到,然后服务端直接发出确认信号,连接就已经建立了。但是客户端当前并没有请求(因为之前的请求已经失效了),但是服务端并不知道这个事情,就一直等待客户端发送数据,这不就是白白等待吗?造成了资源的浪费。
但是在三次握手中,客户端先给服务端发送一个seq=x,服务端收到后,然后给客户端发送一个确认号ack=x+1,就是为了让客户端去确认,服务端收到的这个连接请求是否还有效,因为客户端请求如果失效,那么客户端所持有的seq=也就不存在了,服务端发送的ack=x+1客户端就不会识别,那么客户端也就不会理睬服务端发送的报文,也就不会再去想服务端的确认信号而发出确认,那么服务端收不到客户端的确认信号,就认为客户端没有要求建立此次连接,也就不会等待客户端去发送数据了。这样的好处,既能避免历史连接,又能同步双方初始化序列号,还能避免资源浪费。
3、为什么四次挥手?
在第一个问题中已经说明了,服务端收到FIN结束标志后,这只表示客户端没有数据向服务端发送了,但是服务端可能还有数据要想客户端发送,所以还不能立即关闭连接,所以服务端收到客户端发送的结束请求后,需要先给客户端发送一个ACK确认标志,告诉客户端,我收到你的关闭请求了,你先等我一下,让我先处理完事情再关闭。如果不告诉客户端,客户端就会重复向服务端发送结束请求。然后等待服务端处理完后,服务端再给客户端发送一个FIN结束标志,表示我也搞完了,我们可以都可以关闭请求了。所以一般在关闭连接时,ACK报文和FIN报文是分开发送的。
个人见解,如不正确还望各位大佬指出,文中图片来自网络。