zoukankan      html  css  js  c++  java
  • TCP协议

    TCP的报头

    image

    1. Source Port,Dest Port:源端口和目的端口,和IP层的源IP和目的IP来唯一确定一个socket。
    2. Sequence Number:包的序列号,主要用来解决乱序的问题。
    3. Acknowledgement Numbe:就是ACK——用于确认收到,用来解决不丢包的问题,也会用来进行窗口更新。
    4. Window:滑动窗口,通过接受方来控制发送方,达到流量控制的目的。
    5. TCP Flags:TCP的标志比特位。

    TCP状态机

    TCP是一个面向连接、可靠的字节流协议,其实在网络传输中是没有连接的概念,TCP所谓的连接,提现在它的两端所维护的一个状态机上。

    image

    TCP建立过程

    image

    三次握手过程,主要是通信的双方要互相通知对方自己的初始化的Sequence Number(缩写为ISN:Inital Sequence Number)——所以叫SYN,全称Synchronize Sequence Numbers。也就上图中的 x 和 y。这个号要作为以后的数据通信的序号,以保证应用层接收到的数据不会因为网络上的传输的问题而乱序。

    • 讨论:为什么是三次握手过程,而不是两次握手?
    1. 首先,必须至少两次才能建立连接。而且最后一个ACK始终有可能丢失,奇数次建立链接和偶数次建立连接是不同的
    2. 讨论为什么不是偶数次,试想如果偶数次发送最后一个ACK,那么此时服务器端建立了连接,客户端还没有建立连接。假设此时客户端下线,那么服务端并不知道,只能保持这个连接,极大地浪费服务端的资源。
    3. 如果是奇数次连接,就不会出现上述情况。所以奇数次握手是为了保护服务端。
    • 连接建立超时
      TCP的三次握手协议等价于两次等待,第一次等待是客户端发送了SYN后,等到ACK和对端SYN报文,第二次等待是服务端发送了ACK和SYN后,等待客户端的ACK。一般来讲,等待就意味着可能超时。
      如果是客户端发送SYN以后的等待超时,那么客户端每隔几秒重发SYN报文,直到经过75秒。
      如果是服务器发送SYN以后等到超时,服务器会以1S,2S,4S,8S,16S,32S为间隔重发,整个过程一共63秒,这对服务器资源是一种极大的浪费。

    断连过程

    image

    • 为什么是四次挥手

    由于TCP是全双工的,允许在一段关闭发送通道,表示不再有数据的发送,而接受数据的通道是可以继续使用的。

    • socket的优雅关闭和暴力关闭,close和shutdown的区别
    1. close实际做的事是将socket_fd的内部引用计数值减1,如果内部引用计数不用0,则不做任何其他操作;当引用计数为0时,释放掉sock_fd所占资源,关闭对应的TCP连接。
    2. shutdown不管sock_fd的引用计数值是多少,只是单纯的向对方发送一个FIN报文,断开TCP连接。

    当调用shutdown时,只是关闭了TCP连接的某个方向,具体方向视参数而定,对于sock_fd本身所占用的资源,不做任何工作。

    当调用close时,如果引用计数变为0,那么会释放sock_fd所占用的资源,而TCP连接是sock_fd所占用资源的一部分,所以隐含了TCP的断连过程。

    在客户端close一个sock_fd以后,会将这个sock_fd标记为INVALID SOCKET,但是服务器端收到FIN报文后仍然可以通过其所在端的sock_fd发送数据,但是当客户端TCP协议栈收到数据后,发现这是一个无效的socket,因此会返回一个RST报文。

    TIME_WAIT状态

    TIME_WATI状态主要是产生在TCP连接主动断开方,并且在发送最后一个ACK以后达到这个状态,并且TIME_WAIT会持续2MSL的时间,结束后,处于CLOSED状态。

    • 讨论:TIME_WAIT状态的必要性
    1. 保证最后一个ACK能够到达被动断开方。如果不保持这个状态,假设最后一个ACK丢包,那么超时后被动断开方又发送一个FIN,这是因为连接已经终止,这样不够优雅。
    2. 最重要的原因是,让这个连接所有的数据都在网络中消失。防止产生一个相同四元组的连接,

    TCP的数据交互

    TCP是可靠的传输协议,那么必须要有重传的机制。TCP的重传机制是基于ACK的。我们知道ACK表示的意思是对已经收到数据的确认,并且还表示接下来想要收到的数据的SEQ。

    超时与重传

    TCP的基础重传策略是基于定时器的超时机制的,每当TCP发送了一个报文时,会为这个报文设置一个大小为RTO(重传超时时间)的定时器。

    通过RTT(一个数据包从发送出去到ACK回来的时间)动态改变RTO的时间。

    • RTT的测量:
      image

    在图(a)中,如果按照第一次发送和收到ACK之间的时间差,那么显然,由于第一次发送的报文的ACK丢失,所以,ACK其实去重传报文的ACK,这个时间差显然太大。如果按照重传和ACK之间的时间差,那么会出现(b)中的情况,又会出现时间差太小的情况。

    因此,为了简化RTT的测量:

    1. 忽略重传的报文,只计算正常的报文。
    2. 在一个TCP连接上同时只能有一个计时器在测量RTT。

    补充

    1. TCP还有另外的重传机制,例如连续接受三次ACK.
    2. SACK汇报已经接受到的序列号

    流量控制

    TCP头里有一个字段叫Window,这个字段是接收端告诉发送端自己还有多少缓冲区可以接收数据。于是发送端就可以根据这个接收端的处理能力来发送数据,而不会导致接收端处理不过来。

    TCP的滑动窗口协议主要有两个作用,一是提供TCP的可靠性,二是提供TCP的流控特性。同时滑动窗口机制还体现了TCP面向字节流的设计思路。TCP会话的双方都各自维护一个“发送窗口”和一个“接收窗口”。

    发送窗口:

    image

    发送缓冲区一共有4段:已经发送并得到对端ACK的”,“已经发送但还未收到对端ACK的”,“未发送但对端允许发送的”,“未发送且对端不允许发送”。“已经发送但还未收到对端ACK的”和“未发送但对端允许发送的”这两部分数据称之为发送窗口(中间两部分)

    发送窗口更新规则:

    1. 当ACK=36且window size = 14,左边沿滑动到35后面,右边沿滑动到49后面。
    2. 当ACK=36且window size = 10,左边沿滑动到35后面,右边沿不动。
    3. 当发送了两个字节后,中间蓝绿区域中间的线移动到47后面。

    接受窗口

    image
    接收方每次向发送方发送ACK时,都会向发送方汇报己方的接收窗口大小,发送方会根据接收方的窗口大小(实际上会去拥塞窗口和接收窗口的最小值)来控制发送数据的大小,以保证接收方可以及时处理。
    image

    接受窗口为0

    1. 坚持定时器
      当接收窗口大小为0时,由于不能接收到任何数据,不能接收数据也就意味着不能发送ACK,那么当服务器处理了部分数据,接收窗口不为0时如何通知发送方。

      发送方会定时使用一个坚持定时器来周期性地向接收方查询,以便发现窗口是否增大,这种报文叫窗口探查,该报文包含一个字节的伪数据,这一个字节的数据是必须的,因为TCP不会对一个不带数据的报文进行ACK确认。接收方收到这个报文后,返回一个ACK,ACK中带有接收窗口大小。

    2. 糊涂窗口综合症
      如果服务器返回的接受窗口只有很小的字节,按照发送原则,只能发送很小的字节。但是我们的TCP/IP头部都有40个字节,这样发送效率太低。所以,接受方要有足够大的空间才通知发送方,而发送方有比较多的数据才发送。

    • 对于接受方

      1. 只有可用空间大于等于一个MSS时才通知发送方。
      2. 接收缓冲区有超过一半为空时才通知发送方。
    • 对于发送方

      1. 要发送的报文长度大于一个MSS才发送。
      2. 可以发送至少是接收方通告窗口大小一般的报文段才发送。
      3. 没有还没被确认的数据,也就是收到之前发送数据的所有ACK。

    发送方的策略就是著名的Nagle算法。但是对于一些实时交互应用,Nagle算法需要关闭。

    拥塞处理

    流量控制依赖于发送端和接收端,和网络中的状态无关。拥塞控制用于在网络状态不好,发生丢包的时候处理。

    慢启动(指数增长)

    1. 对于刚建立好的连接,先初始化拥塞窗口cwnd=MSS,即一个报文段的大小,初始化慢启动门限ssthresh,一般为65535,都以字节为单位。
    2. 每收到一个ACK,拥塞窗口就增加一个MSS。
    3. 当cwnd>=ssthresh时,启动拥塞避免算法。

    拥塞避免算法(线性增长)

    每收到cwnd/MSS个ACK,cwnd增加MSS个字节

    拥塞发生时算法

    分为两种情况,一为未收到ACK,即超时重传;二为收到3次重复的ACK

    1. 超时重发
      1. ssthredsh = cwnd / 2
      2. cwnd = MSS
      3. 进入慢启动的过程
        image
    2. 收到3次重复的ACK(说明网络并不是那么糟糕)
      1. cwnd = cwnd / 2
      2. ssthresh = cwnd
      3. 进入快速恢复算法
    • 快速恢复算法

      1. 设置cwnd = cwnd + 3 * MSS,3个MSS对应3个重复的ACK。
      2. 以后每收到一个重复的ACK,cwnd = cwnd + MSS。
      3. 如果收到的是一个新的ACK,那么cwnd = ssthresh,进入拥塞避免算法。
        image
    • 讨论:快速重传为什么选择三次重复ACK来确定,而不是两次或者四次

    重复ACK次数越多,由丢包引起重复的概率就越大,但是次数越多,丢包响应速度就越慢。3次是一种很好的折中。

    TCP避免分段

    MSS

    TCP数据包每次能够传输的最大数据分段。通讯双方会根据双方提供的MSS值得最小值确定为这次连接的最大MSS值。

    分片

    在IP层有一个数据报要进行传输,但是数据的大小比链路上的MTU还要大,那么这是就必须将数据分成若干片进行传输。通常UDP是要进行分片的,因为UDP在传输的时候,本身不会将报文分段,报文长度可能会远远超过链路的MTU,所以UDP的传输依赖IP层的分片进行。

    分片的重组

    IP数据报进行分片以后,由到达目的端的IP层来进行重新组装,其目的是使分片和重新组装过程对运输层(TCP/UDP)是透明的。由于每一分片都是一个独立的包,当这些数据报的片到达目的端时有可能会失序,但是在IP首部中有足够的信息让接收端能正确组装这些数据报片。

    由于IP分片数据再对端重组,但是一旦IP分片丢失任何一片,整个数据包将不能重组,只能被丢弃,所以,一旦TCP报文段进行分片,丢包率会大大上升,导致很多重传问题。所以TCP会尽量在自己的协议层分片。

    总结

    TCP不适用IP层分片,UDP使用IP层分片。ICMP报文控制MSS的大小。

    名词解释

    1. RTT:一个数据包从发送出去到ACK回来的时间
    2. RTO:超时重传时间,根据RTT计算
    3. MSL:TimeWait等待时间
    4. MTU:链路最大传输字节数
    5. MSS:TCP最大传输字节数量,MTU-MSS

    API

    listen

    int listen(int sockfd, int backlog);
    

    Linux对正在建立连接的socket有两个队列,一个是正在建立连接的队列,一个是已经建立连接的队列。

    • 收到SYN,建立未完成的sock,加入正在建立连接的队列
    • 收到ACK,完成上面未完成的sock,加入已经建立连接的队列

    backlog和somaxconn的最小值决定了已经建立连接的队列长度。

    accept

    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    

    accept只是从已建立连接的队列摘下来一个sock结构体,然后建立文件描述符sock关联起来。accept会一直阻塞,直到有一个sock返回

    connect

    int connect(int sockfd, const struct sockaddr *addr,
                       socklen_t addrlen);
    
    • 调用connect函数会发起三次握手建连过程
    • 通常阻塞直到建连成功或者发生错误
    • 非阻塞connect可以防止多次重发syn,等待75秒

    对比

    image

  • 相关阅读:
    linux中批量添加文件前缀的操作
    Opencv中图像height width X 轴 Y轴 rows cols之间的对应关系
    PyCharm 快捷键失效解决办法
    模型权重初始化的可行性分析
    pycharm报错:Process finished with exit code -1073741819 (0xC0000005)解决办法
    损失函数———有关L1和L2正则项的理解
    利用tensorboard可视化checkpoint模型文件参数分布
    linux部署.net Core项目
    Java开发工程师2020最新面试题-适用于2-3年工作经验
    springboot常用注解
  • 原文地址:https://www.cnblogs.com/biterror/p/6909853.html
Copyright © 2011-2022 走看看