java - Client SocketInputStream.close() 导致更多的资源消耗?

标签 java windows performance sockets

如果我执行下面没有“inputStream.close()”行的 JUnit 测试(见下文),可以处理超过 60000 个请求(然后我终止了进程)。有了这条线,我没有发出超过 15000 个请求,因为:

java.net.SocketException: No buffer space available (maximum connections reached?): connect
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
    at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
    at java.net.Socket.connect(Socket.java:529)
    at java.net.Socket.connect(Socket.java:478)
    at java.net.Socket.<init>(Socket.java:375)
    at java.net.Socket.<init>(Socket.java:189)
    at SocketTest.callServer(SocketTest.java:60)
    at SocketTest.testResourceConsumption(SocketTest.java:52)

我在 Windows 上运行它,在开始测试之前我等待 netstat 列表恢复正常。

问题:

  • 在这种情况下,为什么在客户端调用 socketInputStream.close() 会造成伤害?
  • 或者代码有什么问题?

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import junit.framework.TestCase;

public class SocketTest extends TestCase {
    private static final int PORT = 12345;
    private ServerSocket serverSocket;

    public void setUp() throws Exception {
        serverSocket = new ServerSocket(PORT);

        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true) {
                    try {
                        final Socket socket = serverSocket.accept();
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    OutputStream outputStream = socket.getOutputStream();
                                    for(int i = 0; i < 100; i++) {
                                        outputStream.write(i);
                                    }
                                    outputStream.close();
                                    // in fact the previous line calls this already:
                                    // socket.close();
                                } catch (IOException e) {
                                    throw new RuntimeException(e);
                                }
                            }
                        }).start();
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }).start();
    }

    public void testResourceConsumption() throws Exception {
        for (int i=0; i<1000000; i++) {
            callServer();
            if (i % 1000 == 0) {
                System.out.println(i);
            }
        }
    }

    private void callServer() throws Exception {
        Socket clientSocket = new Socket("localhost", PORT);
        InputStream inputStream = clientSocket.getInputStream();
        for (int i = 0; i < 100; i++) {
            assertEquals(i, inputStream.read());
        }
        ///////////////// THIS LINE IS INTERESTING 
        inputStream.close();
        // in fact the previous line calls this already:
        // clientSocket.close();
    }

    public void tearDown() throws Exception {
        serverSocket.close();
    }

}

最佳答案

当您显式调用 inputStream.close() 时,您更改了 TCP 正常连接释放的顺序。在这种情况下,连接的客户端在从服务器接收到 FIN 数据包之前关闭,从而使套接字处于 TIME_WAIT 状态。在某些时候,所有用于传出连接的本地端口都被这些 TIME_WAIT 套接字占用,并且无法建立更多的传出连接。

当您不调用 inputStream.close() 时,服务器端将使用 outputStream.close() 调用关闭连接。客户端套接字有足够的时间从服务器接收 FIN,然后在垃圾回收时它们会被终结器方法优雅地关闭。

有两个选项可以修复测试中的过程:

  1. 更好的方法是继续从inputStream读取,直到收到-1,这意味着对方已经发起连接关闭(即收到FIN)。只需在 inputStream.close();
  2. 之前插入 assertEquals(-1, inputStream.read());
  3. 第二个选项是通过设置强制中止释放
    clientSocket.setSoLinger(true, 0);
    在这种情况下,inputStream.close() 将强制客户端发送 RST 并中止连接。

More about orderly and abortive TCP connection release.

关于java - Client SocketInputStream.close() 导致更多的资源消耗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31966291/

相关文章:

windows - _CrtCheckMemory 使用示例

windows - 如何使用 Perl 从 Windows 命令行获取文件的 SHA1 哈希值?

java - 分割字符串的有效方法

python - Appengine Python 中的并发请求

java - Eclipse 中的 JADE ICP 异常

java - java中如何删除链表中的唯一节点?

windows - Docker + Windows + 普罗米修斯 : How/Where to supply the configuration files

mysql - 在 rake db :migrate 上的多个数据库上运行相同的迁移

java - 为什么加起来是 11 而不是 8?

java - 调整图像大小以适应适应其大小的整个 JLabel