参考资料:

https://huoding.com/2016/01/19/488

示例代码:

https://github.com/gordonklg/study,socket module

A. CLOSE_WAIT

有时会出现服务器响应极慢、假死的现象,查看 netstat 会发现服务器上存在大量未关闭的 CLOSE_WAIT 状态连接。我们分析下原因。

首先,CLOSE_WAIT 是被动关闭方才会出现的状态。我们模拟一个场景,客户端建立大量 Socket 连接,同时为每个 Socket 设置超时时间,并且在发生超时时关闭 Socket;服务器端不发送数据也不关闭 Socket。对应测试代码如下:

gordon.study.socket.basic.wireshark.MockSocketTimeoutThenServerCloseWait_Server.java

public class MockSocketTimeoutThenServerCloseWait_Server {

    @SuppressWarnings("resource")
public static void main(String[] args) throws Exception {
Set<Socket> set = new HashSet<>();
ServerSocket serverSocket = new ServerSocket(8888);
while (true) {
Socket socket = serverSocket.accept();
set.add(socket); // anti gc.
}
}
}

gordon.study.socket.basic.wireshark.MockSocketTimeoutThenServerCloseWait_Client.java

public class MockSocketTimeoutThenServerCloseWait_Client {

    public static void main(String[] args) throws Exception {
for (int i = 0; i < 100; i++) {
Thread.sleep(30);
new Thread(new SocketClient()).start();
}
} private static class SocketClient implements Runnable { @Override
public void run() {
try (Socket socket = new Socket()) {
socket.connect(new InetSocketAddress(8888));
socket.setSoTimeout(1000);
socket.getInputStream().read();
} catch (Exception e) {
System.out.println(e);
}
}
}
}

100个线程创建了100个 Socket 连接,在1秒钟后读超时,留下了100个 CLOSE_WAIT 状态的连接。

CLOSE_WAIT 状态的连接并不占用太多操作系统资源,它只是服务器无响应的一种症状,真正的原因还需要自己分析。

大多数情况下是因为客户端超时直接关闭 Socket,同时服务端没能正确关闭 Socket 导致的。可以通过服务端设置读超时、引入心跳检测等方式修复。

真正的问题是客户端为什么会超时。考虑是否超时时间设置太短、业务流中是否有耗时(但不太耗资源)的操作、是否允许了请求排队但是队伍太长导致等待中就超时了。

B. TIME_WAIT

TIME_WAIT 状态会保持 2 * MSL 时间,这是由 TCP 协议规定的。MSL 是指 TCP 报文段生存的最大时间。

在高并发场景下,例如 TPS 1k,如果 MSL 为60秒,那么可能会有 120k 个 TIME_WAIT 状态的连接。这会占用大量系统资源。

TIME_WAIT 一定是主动关闭方才会有的状态,如下图。我们的模拟场景需要由服务方先关闭 Socket。

gordon.study.socket.basic.wireshark.MockServerTimeWait_Server.java

public class MockServerTimeWait_Server {

    @SuppressWarnings("resource")
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);
while (true) {
Socket socket = serverSocket.accept();
socket.close();
}
}
}

gordon.study.socket.basic.wireshark.MockServerTimeWait_Client.java

public class MockServerTimeWait_Client {

    public static void main(String[] args) throws Exception {
for (int i = 0; i < 100; i++) {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(8888));
InputStream is = socket.getInputStream();
while (is.read() != -1) {
}
socket.close();
}
}
}

最简单的解决方案就是让客户端作为主动关闭方。被动关闭方是没有 TIME_WAIT 的烦恼的。

Java网络编程学习A轮_04_TCP连接异常的更多相关文章

  1. Java网络编程学习A轮_01_目标与基础复习

    A. A轮目标 复习网络编程基础知识,重点学习下TCP三次握手四次挥手,以及可能引发的异常情况. 回顾 Socket 编程,好多年没写(chao)过相关代码了. 重学 NIO,以前学的基本忘光了,毕竟 ...

  2. Java网络编程学习A轮_06_NIO入门

    参考资料: 老外写的教程,很适合入门:http://tutorials.jenkov.com/java-nio/index.html 上面教程的译文:http://ifeve.com/overview ...

  3. Java网络编程学习A轮_08_NIO的Reactor模型

    参考资料: 了解 Java NIO 的 Reactor 模型,大神 Doug Lea 的 PPT Scalable IO in Java 必看:http://gee.cs.oswego.edu/dl/ ...

  4. Java网络编程学习A轮_03_抓包分析TCP四次挥手

    参考资料: http://www.jellythink.com/archives/705 示例代码: https://github.com/gordonklg/study,socket module ...

  5. Java网络编程学习A轮_07_基于Buffer的Socket编程

    示例代码: https://github.com/gordonklg/study,socket module A. LineSeparate 基于 Buffer 实现逐行读取的 EchoServer ...

  6. Java网络编程学习A轮_05_Socket编程

    示例代码: https://github.com/gordonklg/study,socket module A. Socket 编程简单例子 最简单的 Socket 编程是通过回车/换行符,整行读取 ...

  7. Java网络编程学习A轮_02_抓包分析TCP三次握手过程

    参考资料: https://huoding.com/2013/11/21/299 https://hpbn.co/building-blocks-of-tcp/#three-way-handshake ...

  8. Java 网络编程学习总结

    新手一枚,Java学习中,把自己学习网络编程的知识总结一下,梳理下知识,方便日后查阅,高手莫进. 本文的主要内容: [1]    网络编程认识                [2]  TCP/IP编程 ...

  9. Java网络编程学习笔记

    Java网络编程,我们先来看下面这一张图: 由图可得:想要进行网络编程,首先是服务器端通过ServerSocket对某一个端口进行监听.通过accept来判断是否有客户端与其相连.若成功连上,则通过r ...

随机推荐

  1. 基于JDK1.8的LinkedList源码学习笔记

    LinkedList作为一种常用的List,是除了ArrayList之外最有用的List.其同样实现了List接口,但是除此之外它同样实现了Deque接口,而Deque是一个双端队列接口,其继承自Qu ...

  2. 全角半角符号引发的Entity Framework奇遇记

    SQL Server的SQL查询不区分大小写,而LINQ查询区分大小写,所以在写LINQ代码时需要注意的是——如果这段LINQ代码将会被Entity Framework解析为SQL语句(LINQ to ...

  3. Swap---hdu2819(最大匹配)

    题意:通过交换行或者列来实现对角线(左上角到右下角)上都是1, 首先,如果某行全是0或者某列全是0必然不满足情况输出-1,如果能转换的话,那么必然可以通过全由行(列)变换得到: 还有就是对角线上的N个 ...

  4. keras实现不同形态的模型

    keras提供了Sequential线性的模型,但是有些网络需要多个输入,有些网络有多个输出,更甚之层与层之间有内部分支,这使得网络看起来像是层构成的图,而不是线性的堆叠.有些场景需要多模态的输入,这 ...

  5. cocos代码研究(18)Widget子类Slider学习笔记

    理论基础 滑动条控件. 代码实践 实例: // Create the slider Slider* slider = Slider::create(); slider->loadBarTextu ...

  6. #C++初学记录(高精度运算)(加法)

    高精度运算 不管是int还是double亦或者long long ,这些定义变量都有数据范围的一定限制,在计算位数超过十几位的数,也就是超过他们自身的数据范围时,不能采用现有类型进行计算,只能自己通过 ...

  7. poj1151 Atlantis && cdoj 1600艾尔大停电 矩形面积并

    题目: Atlantis Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 23758   Accepted: 8834 Des ...

  8. uva1291

    这题说的给了 一 个 图,每次 按照他给的顺序 跳格子 给了 每种 格子之间的 转换 代价 求最后 转换代价 dp[i][j] 表示 左脚在i 右脚 在j 的最小代价 然后用滚动数组 ,就可以不断说的 ...

  9. spark环境安装

    源码包下载: http://archive.apache.org/dist/spark/spark-2.1.1/v 集群环境: master 192.168.1.99 slave1 192.168.1 ...

  10. 网关服务Spring Cloud Gateway(一)

    Spring 官方最终还是按捺不住推出了自己的网关组件:Spring Cloud Gateway ,相比之前我们使用的 Zuul(1.x) 它有哪些优势呢?Zuul(1.x) 基于 Servlet,使 ...