zoukankan      html  css  js  c++  java
  • TCP(二)

    TCP半连接和全连接问题

    TCP握手过程详解

    如上图所示,关键部分:syns queue(半连接队列)和accept queue(全连接队列)

    正常情况下的处理过程如下:

    1)当server端收到client发送的SYN后,将连接相关信息放在syns queue中,并回复SYN+ACK;

    2)当server端收到client发送的ACK后,将连接相关信息从syns queue中取出并放在accept queue中。

     异常情况:

    步骤2)中如果accept queue满了,则根据tcp_abort_on_overflow指定的策略执行

      如果tcp_abort_on_overflow为0,server丢弃client发送的ack,并且在一段时间后再次发送syn+ack给client(即重新走握手的第二步),如果cilent的超时时间比较短,就会出现异常;重试次数由net.ipv4.tcp_synack_retries指定(centos默认5次);

      如果tcp_abort_on_overflow为1,server将发送一个reset给client,表示要废掉这次握手过程和连接。此时client应该会出现connection reset by peer异常。

    怎么查看队列是否满?

    netstat -s

      该命令查看每个协议的统计数据

    netstat -s | egrep "listen" 

      如果看到:XXXX times the listen queue of a socket overflowed 并且XXXX 值在不断增加,就说明有全连接队列偶尔满了。

    ss -lnt | grep port

    State         Recv-Q      Send-Q        Local Address:Port        Peer Address:Port
    LISTEN     0                50                :::9188                            :::*

    其中Send-Q为监听9188端口的全连接队列最大为50,Recv-Q表示全连接队列中和等待进入全连接的数量。

    全连接队列的大小取决于:min(backlog, somaxconn) . backlog是在socket创建的时候传入的(Java Socket默认为50),somaxconn是一个os级别的系统参数

    半连接队列的大小取决于:max(64, /proc/sys/net/ipv4/tcp_max_syn_backlog)。 不同版本的os会有些差异.

    CLOSE-WAIT问题

    什么情况下会出现CLOSE-WAIT状态

      在被动关闭连接时,已经收到对方发来的FIN(并发送了ACK),但还没有发送自己的FIN时,处于CLOSE_WAIT状态。

    正常情况下该状态持续的时间应该很短,出现大量close_wait的现象,主要原因是某种情况下对方关闭了socket链接,但是我方忙与读或者写,没有关闭连接。

    产生该问题的例子:https://blog.csdn.net/yu616568/article/details/44677985

      首先,我这边的大部分请求都需要查询数据库,我的数据库连接池设置的最大连接数是100,所以每一个请求创建了一个连接,等到100个请求就把连接池占满了,但是处理servlet的那个线程并没有释放这个连接,于是接下来的请求再去创建数据库连接的时候就会一直阻塞在那里,这里我所用的是DBCP作为连接池的,它的实现好像是使用apache的objectPool来实现的,如果没有可用的连接对象会导致线程等待,好了,servlet由于得不到数据库连接而阻塞了,这个客户端的请求就一直等待,客户端使用httpclient设置了5s的请求超时时间,那么超时之后就会抛出异常,关闭连接,关闭连接导致客户端发送了FIN报文,我这边的TCP/IP返回了ACK报文,但是由于处理请求的线程还处于阻塞的状态,所以当前的连接状态时CLOSE_WAIT。

    解决方法
    基本的思想就是要检测出对方已经关闭的socket,然后关闭它

    1.代码需要判断socket,一旦read返回0,断开连接,read返回负,检查一下errno,如果不是AGAIN,也断开连接。(注:在UNP 7.5节的图7.6中,可以看到使用select能够检测出对方发送了FIN,再根据这条规则就可以处理CLOSE_WAIT的连接)
    2.给每一个socket设置一个时间戳last_update,每接收或者是发送成功数据,就用当前时间更新这个时间戳。定期检查所有的时间戳,如果时间戳与当前时间差值超过一定的阈值,就关闭这个socket。
    3.使用一个Heart-Beat线程,定期向socket发送指定格式的心跳数据包,如果接收到对方的RST报文,说明对方已经关闭了socket,那么我们也关闭这个socket。
    4.设置SO_KEEPALIVE选项,并修改内核参数

    TCP协议在带宽利用率、性能方面的优化 

    delay ack

      

    Nagle算法

    参考资料

    服务器TIME_WAIT和CLOSE_WAIT详解和解决办法

    CLOSE_WAIT状态的原因与解决方法

    关于TCP 半连接队列和全连接队列

    就是要你懂 TCP | 最经典的TCP性能问题

  • 相关阅读:
    牛客网 二叉树的镜像 JAVA
    牛客网 反转链表 JAVA
    牛客网 调整数组顺序使奇数位于偶数前面 JAVA
    Integer to Roman LeetCode Java
    Valid Number leetcode java
    Longest Common Prefix
    Wildcard Matching leetcode java
    Regular Expression Matching
    Longest Palindromic Substring
    Add Binary LeetCode Java
  • 原文地址:https://www.cnblogs.com/zaizhoumo/p/8889320.html
Copyright © 2011-2022 走看看