TCP协议

461 阅读6分钟

特点

  • 面向连接
  • 可靠
  • 流式服务

报文

  • 16位端口号:告知主机该报文段来自哪里(源端口号)要传给那个上层协议或应用程序(目的端口号)。

  • 32位序号:一次TCP通信过程中某一个传输方向上的字节流的每个字节的编号。A发送给B的第一个报文段中,序号值被系统初始化为某个随机值ISN,后续在该方向上的TCP报文段的序号值被设置为ISN加上该报文段所携带数据的第一个字节在整个字节流中的偏移。

  • 32位确认号:另一方对TCP报文段的响应,其值是收到的TCP报文段的序号值加1。

  • 4位头部长度:标识该TCP头部有多少个32位(即有多少行),因为4位最大能表示15,所以TCP头部最长是60字节。

  • 6位标志:

    • URG标志:紧急指针是否有效。

    • ACK标志:确认号是否有效。称携带ACK标志的TCP报文段为确认报文段。

    • PSH标志:提示接收端应用程序应该立即从TCP接受缓冲区中读走数据,为接受后续数据腾出空间。TCP缓冲区  在网卡上,有大小限制,如果应用程序一直不读取就会一直在缓冲区,影响后续数据。

    • RST标志:表示要求对方重新建立连接。称携带RST标志的TCP报文段为复位报文段。

    • SYN标志:请求建立连接。称携带SYN标志的TCP报文段为同步报文段。

    • FIN标志:通知对方本段要关闭连接。称携带FIN标志的TCP报文段为结束报文段。

  • 16位窗口大小:TCP流量控制的一个手段。这里窗口指接收通告窗口。告诉对方本端的TCP缓冲区还能接收多大字节的数据,避免发过来接收不了,数据丢失。

  • 16位校验和:发送端填充,接收端对TCP报文段执行CRC算法检验TCP报文段在传输过程中是否损坏。不仅检验头部也检验数据部分。

  • 16位紧急指针:它和序号值相加表示最后一位紧急数据的下一字节的序号,这部分为紧急数据先处理。

TCP可靠性

  • 32位序号:保证数据有序;

  • 32位确认号与超时重传机制:保证报文段不会丢失;

  • 6位标志:说明报文段的类型;

  • 16位窗口大小:告诉对方本端TCP缓冲区还能容纳多少字节的数据,这样对方可以控制发送数据的速度,保证发送的数据流量不会超过容纳范围,也就保证了不会丢失数据;

  • 校验和:保证数据的准确性。

TCP的超时重传机制

TCP模块为每个TCP报文段都维护一个重传定时器,该定时器在TCP报文段第一次被发送时启动,如果超过时间没有收到对方确认,就重传并重置定时器。至于超时多长时间重传或重传多少次,就看TCP的重传策略。

每次重传超时时间都增加一倍,因为比如说第一次0.2s没有成功,那再传时0.2s也不会成功,所以增加一倍。当达到最大重传次数,底层的IP和ARP开始接管,直到客户端放弃连接。Linux有两个重要的内核参数与TCP超时重传相关:/proc/sys/net/ipv4/tcp_retries1(底层IP接管之前最少重传的次数,默认值为3)和/proc/sys/net/ipv4/tcp_retries2(放弃连接前TCP最多可以重传的次数默认值为15)。

面向连接

  • 三次握手

    • 客户端建立TCB主动打开,服务器建立TCP被动打开进入LISRTEN状态;
    • 客户端发送SYN同步报文段(SYN=1,seq=x),请求建立链接;
    • 服务器收到请求后,同意建立连接,发送ACK确认报文(ACK=1,SYN=1,ack=x+1,seq=y)
    • 客户端收到确认报文后,给服务器发送ACK确认报文(ACK=1,ack=y+1,seq=x+1)
  • 为什么客户端还要发送一次确认呢?

TCP有超时重传机制,客户端发送一次连接长时间没有收到确认,客户端会再次发送连接请求。如果第一次因为报文段丢失没有收到确认,第二次正常建立连接,数据传输后释放连接;如果第一次是因为报文段在某些网络节点长时间滞留,以致于连接释放以后才到达服务器,本来这是一个已经失效的报文段,但是服务器收到以后,会误认为这是客户端新发送的一次连接请求,服务器端发送确认报文段同意连接,如果没有第三次确认,连接就建立了。但是客户端并没有发送连接请求,也不会发送数据,服务器就会一直等待,浪费资源。也就是说,客户端再发送一次确认主要是为了防止已失效的连接请求报文段突然又传送到服务器端而产生错误。

  • 四次挥手 TCP连接的释放客户端和服务器都可以先发起,这里以客户端发起断开连接请求为例。

    • 客户端先向服务器发送FIN结束报文,并停止发送数据;
    • 服务器收到发送ACK确认报文,此时服务端进入CLOSE_WAIT状态;
    • 服务器到客户端方向的连接并未关闭,如有数据未发送完毕,继续发送。发送完毕后向客户端发送FIN报文,等待客户端确认;
    • 客户端发出ACK确认报文,进入TIME_WAIT状态,等待2MSL事件后关闭。

这里有一点要注意,这是TCP连接还没有释放掉,必须经过2MSL(最长报文短寿命)时间后,大约2分钟才能结束。

  • 为什么必须在TIME_WAIT状态等待2MSL的时间呢?

    • 可靠地终止TCP连接。要保证最后一个ACK能够到达,如果服务器端没有没有收到最后一个ACK,就会超时重传,但是客户端已经结束了,服务器没有办法正常的终止连接。

    • 保证让迟来的TCP报文段(已失效的报文段)有足够的时间被识别并丢弃。在TIME_WAIT状态时,无法使用该链接占用的端口号建立新的连接。如果没有TIME_WAIT状态,迟来的报文段(已经失效的报文段)会出现在下一次的连接中,但实际上是应该被丢弃的。因为TCP报文段的最大生存时间是MSL,所以坚持2MSL时间可以确保网络上两个传输方向上尚未被收到的、迟到的TCP报文都已经消失(被中转路由丢弃)。因此必须在TIME_WAIT状态等待2MSL的时间。

部分图片来源:blog.csdn.net/sinat_36629…