简介
传输控制协议(Transmission Control Protocol,简称TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议,应用层向TCP层发送用于网间传输的用8位字节表示的数据流,TCP将数据流做分隔处理后透传给IP层,然后由IP层将数据传输给目标端TCP层。
TCP为保证不发生丢包,会对所有的包进行编号,接收端依据编号按序接收,全部数据包接收完成后按序号进行合并,这里可能会发生粘包、拆包的问题(暂不介绍)。接收端在每次接收到数据包的时候都会返回给发送端一个确认信息(ACK),若发送端在一定时间内未接收到ACK信息,则主观认为数据发送失败或数据丢失,会重新发送丢失序号的包。
三次握手
TCP在发送数据之前,需要先建立连接,客户端主动,TCP使用三次握手的方式建立连接,三次握手的意思就是客户端和服务端进行三次通信,三次握手的目的是为了确认通信双方的发送和接收能力是否正常。主要过程:
-
第一次握手:客户端:服务端,我想要向你发送数据
- 客户端向服务端发送一个SYN包,并指明客户端的初始化序列号ISN,随后客户端进入SYN_SEND状态。
- 同部位SYN=1,初始序列号seq=x,此报文不能携带任何的数据,却会消耗掉一个序列号
-
第二次握手:服务端:客户端,我准备好了,你可以把数据发过来了
- 服务端接收到客户端发送的消息,需要返回一个SYN/ACK包进行响应,否则客户端会以为消息跑丢了造成重发,SYN/ACK以服务端的为准,SYN=1, ACK=x+1
- 服务端响应消息也属于是一次通信,所以服务端需要将自己的序列号放入到报文中携带给客户端,初始化序列号seq=y
- 总的响应报文:SYN=1 ACK=x+1 seq=y
- 服务端进入SYN_RECV状态
-
第三次握手:客户端:服务端,我知道了,敌人还有三秒到达战场
- 客户端接收到服务端的响应之后,要告诉服务端老子收到你的响应了,不要以为消息丢了,等着接收数据吧您嘞
- 这次握手等于是服务端响应的翻版,报文包括ACK=y+1 seq=x+1
- 客户端和服务端均进入ESTABLISHED(TCP连接成功)状态
为什么使用三次握手,两次是否可以?
*** 之所以进行三次握手,是保证客户端和服务端均可以进行一次发送、接收和发送接收反馈,目的是让客户端和服务端各自确认自己的发送和接收能力都正常**
四次挥手
TCP发送完数据之后,需要将连接断开,当然断开连接的也需要客户端主动发起,因为数据是否发送完毕只有发送者知道。断开连接需要通过四次挥手(也可以叫四次握手)来保证合理性。
- 第一次挥手:客户端:我数据发送完了,可以断开连接了,我先进入准备断开状态
- 客户端发送完数据之后,向服务端发送断开请求报文,FIN=1 seq=u
- 客户端进入FIN-WAIT-1状态,等待服务端的响应
- 表示客户端没有数据要发给服务端了
- 第二次挥手:服务端:我收到了,我同意你的请求,但我要看下我是否还有数据尚在发送,你等会
- 服务端接收到客户端的断开请求之后,根据序列号进行反馈,ACK=1 seq=v ack=u+1
- 服务端反馈之后进入CLOSE-WAIT状态,客户端接收到反馈之后进入FIN-WAIT-2状态,等待服务端的确认断开请求
- 第三次挥手:服务端:我的数据也都发完了,可以断开了
- 服务端再处理完自己的事情之后,向客户端发送确认断开报文,FIN=1 ACK=1 seq=w ack=u+1
- 这里的ack=u+1,发现和第二次挥手时候的ack一模一样,这也就是和客户端的断开请求对应起来,否则把别的给断开了岂不是很尴尬
- 服务端进入LAST-ACK状态,等待客户端的回应
- 第四次挥手:客户端:我知道了,断开
- 客户端接收到确认断开报文后,向服务端反馈断开报文,ACK=1 seq=u+1 ack=w+1
- 服务端接收到反馈后关闭连接
- 客户端等待2MSL后关闭连接
看一个官方描述图片:
为什么要等待2MSL
-
目的是防止ACK消息丢失,服务端重发消息后可以再次接收并反馈;
-
如果在第三次挥手反馈后客户端立刻关闭,如果反馈报文丢失,那么服务端可能就会一直处于重发第三次挥手的报文中,服务端将无法正常进入关闭状态
-
如果第四次挥手的报文丢失,服务端会再次发送确认关闭消息,客户端重新等待2MSL