TCP的位码,有6个,当它们的值为1时它们是:
SYN,表示建立连接
FIN,表示关闭连接
ACK,表示响应
PSH,表示有DATA传输
RST,表示连接重置
URG,表示紧急比特
为什么不是两次或四次握手
三次握手:“喂,你听得到吗?”
“我听得到呀,你听得到我吗?”
“我能听到你,今天balabala……”
两次握手:“喂,你听得到吗?”
“我听得到呀”“喂喂,你听得到吗?”
“草,我听得到呀!!!!”
“你TM能不能听到我讲话啊!!喂!”
“……”
四次握手:“喂,你听得到吗?”
“我听得到呀,你听得到我吗?”
“我能听到你,你能听到我吗?”
“……不想跟傻逼说话”
为什么要四次挥手
概括来说,为什么要四次挥手呢(最简单的:客户端和服务器都要发送FIN报文,表示没数据需要传送了)?因为TCP有个半关闭状态,如果仅仅是client发送FIN给server端,server端收到FIN返回ack确认的话,这仅仅表明client没有数据要发送了,但是仍然可以接受数据, 这叫半关闭。然后server端要发送FIN报文,表示要释放连接,然后client收到后发出ack确认,server收到返回ack确认后,就断开连接了。
序号(seq)是表示这个报文的起始字节号码 下一个报文的序号是上一个报文的序号加上上一个报文的长度 这样就能够表示上一个报文全部接受了
ack是对收到的数据包的确认,值是等待接收的数据包的序列号。
SYN不能携带数据,要消耗一个序号,FIN即使不携带数据,也要消耗一个序号,ACK不携带数据就不会消耗序号。
TCP作为一种可靠的传输控制协议,它的核心思想在于: 既要保证数据可靠传输,又要提高传输的效率。因为信道是不可靠的,为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。
TCP建立连接的过程叫做握手,握手需要在客户和服务器之间交换三个TCP报文段
首先,客户端与服务器均处于未连接状态,并且是客户端主动向服务器请求建立连接:
客户端将报文段中的SYN=1,并选择一个初始序号seq=x,(即该请求报文的序号为x) 将这个报文发送到服务器。此时,客户端进入同步已发送状态(SYN-SEND).SYN报文段不能携带数据,但是要消耗掉一个序号。下一个序号就是x+1
服务器收到请求报文后,若同意建立连接,则回复报文中,SYN=1,ACK=1,并选择一个初始序号seq = y,且报文中确认号为x+1.此时服务器进入同步已接收状态(SYN-RCVD)
客户端收到服务器的同步确认后,还要向服务器给出确认。将ACK=1,确认号为y+1,而自己的序号seq=x+1(之前消耗一个序号了),将该报文发出后,客户端进入已连接状态(ESTABLISHED)。(ACK报文段可以携带数据,不携带数据就不消耗序号,所以下一个报文的序号仍是x+1)
服务器收到客户端的确认后,也进入已连接状态。
为什么A最好还要发送一次确认呢?这主要是为了防止已失效的连接请求报文段突然又传送到了B,采用两报文握手,B收到已废弃的A的连接请求就在等待A,可这个请求已经被废弃了,A根本就不理财B,结果B一直等待,浪费了大量资源。
以上即三次握手
TCP连接的释放(四次挥手)
连接的释放较连接的建立复杂。
现假设客户端与服务器均处于连接建立状态,客户端主动断开连接:
1.客户端向服务器发送FIN报文:FIN=1,序号seq=上一个最后传输的字节序号+1=u,发送后,客户端进入FIN-WAIT-1状态。
2.服务器接收到该报文后,发送一个确认报文:令ACK=1,确认序号ack = u+1,自己的报文序号seq=v,发送后,服务器进入CLOSE-WAIT状态。
3.此时TCP连接进入连接半关闭状态,服务器可能还会向客户端发送一些数据。
4.客户端收到来自服务器的确认之后,进入FIN-WAIT-2状态。等待服务器发送连接释放报文。
5.如果服务器已经没有要发送的数据,则释放TCP连接,向客户端发送报文:令FIN=1,ACK=1,确认号ack =u+1,自己的序号seq = w(w可能等于v也可能大于v),服务器进入LAST-ACK状态。
6.客户端收到服务器的连接释放报文后,对该报文发出确认,令ACK=1,确认号ack=w+1,自己的序号seq=u+1,发送此报文后,进入TIME-Wait状态,等待2个msl时间后,进入CLOSED状态。
7.服务器收到客户端的确认后,也进入CLOSED状态并撤销传输控制块。
通俗描述3次握手就是
A对B说:我的序号是x,我要向你请求连接;(第一次握手,发送SYN包,然后进入SYN-SEND状态)
B听到之后对A说:我的序号是y,期待你下一句序号是x+1的话(意思就是收到了序号为x的话,即ack=x+1),同意建立连接。(第二次握手,发送ACK-SYN包,然后进入SYN-RCVD状态)
A听到B说同意建立连接之后,对A说:以确认你同意与我连接(ack=y+1,ACK=1,seq=x+1)。(第三次握手,A已进入ESTABLISHED状态)
B听到A的确认之后,也进入ESTABLISHED状态。
1.A与B交谈结束之后,A要结束此次会话,对B说:我要关闭连接了(seq=u,FIN=1)。(第一次挥手,A进入FIN-WAIT-1)
2.B收到A的消息后说:确认,你要关闭连接了。(seq=v,ack=u+1,ACK=1)(第二次挥手,B进入CLOSE-WAIT)
3.A收到B的确认后,等了一段时间,因为B可能还有话要对他说。(此时A进入FIN-WAIT-2)
4.B说完了他要说的话(只是可能还有话说)之后,对A说,我要关闭连接了。(seq=w, ack=u+1,FIN=1,ACK=1)(第三次挥手)
5.A收到B要结束连接的消息后说:已收到你要关闭连接的消息。(seq=u+1,ack=w+1,ACK=1)(第四次挥手,然后A进入CLOSED)
6.B收到A的确认后,也进入CLOSED。
客户端状态变化:未连接—–>SYN-SEND—–>ESTABLISHED—–>FIN-WAIT-1—–>FIN-WAIT-2—–>TIME-WAIT—–>CLOSED
服务器状态变化:未连接—–>SYN-RCVD—–>ESTABLISHED—–>CLOSE-WAIT—–>LAST-ACK—–>CLOSED