参考资料:

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 的烦恼的。

最新文章

  1. 如何使用 Entity Framework 构造动态查询表达式
  2. 延时程序执行Qt
  3. hdu 1114 Piggy-Bank
  4. Android -- 简单的图片浏览器
  5. MyEclipse使用总结——MyEclipse去除网上复制下来的来代码带有的行号
  6. iOS实现(超级猜图)源码
  7. 2015 ACM/ICPC Asia Regional Beijing Online
  8. NSAutoReleasePool
  9. linux下mysql数据库的学习
  10. spring对数据库特殊字段的支持
  11. sql 字段字符串内容替换
  12. Vim常用操作-合并行。
  13. KV型内存数据库Redis
  14. 如何从GitHub下载csv文件
  15. linux_shell 编程学习-初识she&#39;ll
  16. Java基于opencv实现图像数字识别(三)—灰度化和二值化
  17. Equal 路由类
  18. 关于itext生成pdf的新的demo(包含简单的提取txt文件的内容 和xml内容转化为pdf)
  19. Jmeter远程测试
  20. WPF Storyboard 动画播放完毕时触发的事件

热门文章

  1. 设备信息的管理(Device) ---- HTML5+
  2. R的grep和grepl
  3. C /C ++中结构体的定义
  4. scrapy爬虫系列之五--CrawlSpider的使用
  5. 禁止输入emoji表情
  6. 2.wireshark分析之TCP协议(一)
  7. 解决 Ubuntu 下 Sublime Text 无法输入中文的问题
  8. UVA 624 ---CD 01背包路径输出
  9. 洛谷P1156 垃圾陷阱 dp
  10. remote git server