TCP

tcp报文段首部

  • 最前面两个分别是源端口和目的端口,各占2个字节
  • Sequence Number是包的序号,用来解决网络包乱序(reordering)问题(seq是初始化序号的简称)。
    • 比如:一段报文,seq为301,携带100字节的数据,表明第一个字节的序号是301,最后的字节序号是400,期望下一个报文段的数据序号从401开始,则服务器或客户端发的下一个报文段的序号字段应为401.
  • Acknowledgement Number就是ACK——用于确认收到,用来解决不丢包的问题。(此为确认号,并非tcp flag的ACK)
    • 期望收到对方下一个报文段的第一个数据字节序号。如若ACKnum = N,则表明到N-1为止的所有数据都已经正确收到。
  • TCP Flag ,也就是包的类型,主要是用于操控TCP的状态机的。
    • URG:当TCP Flag中的URG为1时,则表明紧急指针字段有效,告诉操作系统,报文段中有紧急数据、
    • ACK:仅当ACK =1时,确认号才有效。当ACK = 0时,确认号是无效的。TCP规定,在连接建立后所有传送的报文段都必须把ACK设为1。(有效的确认连接已经建立)
    • PUSH(推送):当这个设置为1时,接收方会尽快的将收到的报文段交付给接受应用进程,而不等到缓存满了再交付
    • RST(复位):当收到的报文段rst为1时,表明tcp连接中出现严重的差错,必须释放连接,然后再重新建立连接,还用来拒绝一个非法报文段和拒绝打开一个连接。
    • SYN(同步):在连接建立时用来同步序号。当SYN =1而ACK =0时,表明这是一个请求连接报文段。对方若同意建立连接,则应当在响应报文段中使用SYN=1 和ACK =1。
    • FIN(终止): 用来释放一个连接,当FIN = 1 时,表明此报文段的发送方的数据已经发送完毕,并要求释放连接。
  • Window又叫Advertised-Window,也就是著名的滑动窗口(Sliding Window),用于解决流控的
    • 窗口指的是发送本报文段的一方的接受窗口。窗口值告诉对方:本报文段首部的确认好算起,接收方目前允许对方发送的数据量。窗口值作为接收方让发送方设置其发送窗口的依据
    • 比如,确认号是701,窗口字段是1000,这就表明,从701�号算起,发送此报文段的一方还有接受1000个字节数据(字节序号是701~1700)的接受缓存空间。

tcp三次握手

  • TCP是面向连接的协议,为什么要三次握手呢?
    • 要使每一方能够确知对方的存在
    • 避免了服务器资源的浪费,预防连接请求延迟到达时,服务器依旧打开连接等待客户端。
  • 默认情况下,client(客户端)为主动打开连接,server(服务端)为被动打开连接。
  • 1.一般服务器进程会先创建传输控制块TCB,准备接受客户端的连接请求,然后服务器进程就处于listen(监听)状态,等待连接请求。
  • 2.client进程在发起连接之前也会创建一个TCB,然后向server发出连接请求报文段,这时候首部的同步位SYN =1,同时会选择一个初始化序号seq = x。tcp规定,SYN报文段不能携带数据,但要消耗一个序号,这时候发送完SYN报文后,client进入SYN-SENT(同步已发送)状态.
  • 3.server收到请求报文段后(SYN报文),如同意建立连接,则向client发送确认报文段,在确认报文段首部把SYN位和ACK位都设置为1.,然后AckNum确认号 为x+1,同时也为自己选择一个初始化序号seq = y
    在此报文段中依然不能携带数据,但同样要消耗掉一个序号,此时server进入SYN-RCVD(同步收到)状态
  • 4.此时client收到server的确认后,还要给server发送确认,此时是第三次握手。发送的确认报文段ACK置1确认号AckNum为 ack= y+1.而自己的序号seq = x+1,这时候,tcp规定可以携带数据,但不携带数据则不消耗序号。这说明,下一个数据报文段的seq仍是 x+1.这时候。tcp连接已经建立,client也进入ESTABLISHED(已建立连接状态).
  • 5.当server收到client的确认后,也进入了ESTABLISHED状态
  • 三次握手主要是为了防止已失效的连接请求报文突然又传送到server,因而产生错误,从而浪费server的资源。有了第三次的话,client不发送第三次确认server的确认,server由于收不到第三次确认,就是的client并没有需要建立连接。

四次握手,释放连接

  • 1.同理三次握手,client先发送一个连接释放报文段给server,并停止发送数据,主动关闭tcp连接,这个报文段的首部将tcp flag中的FIN为设置为1,然后将seq = u,等于把前面已传送过去的数据最后一个字节+1.此时client由ESTABLISHED状态进入FIN-WAIT-1(终止等待1)状态。等待server的确认,请注意,FIN报文段即使不携带数据,也会消耗一个序号。

  • 2.当server收到FIN报文后,会立即发出确认ack=1,ACKnum =u +1,然后自己的序号为v,发出去后则进入CLOSE-WAIT(关闭等待)状态.这个时候server会通知高层应用进程,这时TCP连接进入半关闭(half-close)状态,就是client已经没有数据发给server,而server如果还有数据发给client,client仍要接收,这个状态还持续一段时间。

  • 3.当client收到server的确认后,就进入了FIN-WAIT-2(终止等待2)状态,等待server发出关闭连接报文。

  • 4.当server已经没有更多数据要向client发送的时候,就会发出server的FIN报文段,然后必须重复发送上次的确认号AckNum为 ack= u+1,在设置自己的序号seq=w此时server就会进入LAST-ACK(最后确认)状态,等待client的确认。

  • 5.当client受到server的连接释放报文后,必须对此发出确认。在确认报文段把ack置1确认号AckNum为 ack= w+1。而自己的序号为 seq = u+1。然后则进入 TIME-WAIT。此时TCP连接还没释放,必须等待2MSL(2次最长报文段寿命:2*2分钟).等待完后才进入CLOSED状态,而server收到最后ACK的时候就会进入CLOSED,比client早一点。

  • 为什么需要等待2MSL时间呢?

    • 1.为了保证client发送的最后一个ACK报文段能够到达server,假如,这个最后ACK报文段丢失了,则server就处在LAST-ACK状态中,一直收不到自己刚刚发给client的FIN+ACK的报文段的确认报文。server就会再次重传一次FIN+ACK。而client就能在2MSL时间内收到重传的FIN+ACK报文,从而client在最后TIME-WAIT的状态中可以再次重传一次对server的FIN+ACK报文的确认报文。重启2MSL计时器。
    • 这样如果client不在TIME-WAIT等待一段时间,而是在发送第一次ACK报文后立即释放连接,如果这个ACK报文丢失后,就无法收到server重传的FIN+ACK报文,因而不会再次发送ACK报文段,server就无法正常进入CLOSED状态。
    • 2.还有一个原因是为了防止已经失效的报文段在新的连接中出现。因为client发送完最后一个ACK报文段后,等待2MSL后,会使本次连接内所有产生的报文段在网络中小时。

总结

  • 无论三次握手与四次握手,双方的序号seq与acknum都要保持同步,比如server发送seq =x,client则会发送acknum=x+1.
  • 每次握手都需要确认上一次握手,tcp flag中的标志位是发起连接或者释放连接的关键。

参考:http://coolshell.cn/articles/11564.html

你可能感兴趣的:(TCP)