【问题标题】:Java Sockets: No buffer space available (maximum connections reached?)Java 套接字:没有可用的缓冲区空间(达到最大连接数?)
【发布时间】:2014-10-17 07:24:13
【问题描述】:

我有一个大问题。我开发了一个客户端-服务器应用程序。客户端线程向服务器发送一个序列化的对象,服务器返回一个序列化的对象。目前我正在使用一台服务器和 10 个客户端线程,大约 30 秒后,我从每个客户端线程(IOException)收到错误消息:

没有可用的缓冲区空间(已达到最大连接数?):连接

如果我在 netstat 中查看,那么我会看到创建了很多连接,而且它还在不断增长,所有连接都处于 TIME_WAIT 状态。

我不知道为什么。我每次在 finally 块中关闭服务器和客户端中的套接字。这是一些代码:

在我的 socketHandlerThread 中的服务器中:

ServerSocket serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(5000);
while(true) {
       Socket socket = serverSocket.accept();
}

然后将新套接字放在 LinkedBlockingQueue 上,工作线程获取套接字并执行以下操作:

try {
      outputStream = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
      outputStream.flush();
      inStream = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
      ClientRequest clientRequest = (ClientRequest) inStream.readObject();
...
      outputStream.writeObject(serverResponse);
      outputStream.flush();
} catch....
} finally {
                if (inStream != null) {
                    inStream.close();
                }
                if (outputStream != null) {
                    outputStream.close();
                }
                if (socket != null) {
                    socket.close();
                }
}

在客户端我有以下代码:

    try {
        socket = new Socket(host, port);
        outputStream = new ObjectOutputStream(new BufferedOutputStream(socket.getOutputStream()));
        outputStream.flush();
        inputStream = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
        outputStream.writeObject(request);
        outputStream.flush();
        Object serverResponse = inputStream.readObject();
   } catch....
   } finally {
            if (inputStream != null) {
                inputStream.close();
            }
            if (outputStream != null) {
                outputStream.close();
            }
            if (socket != null) {
                socket.close();
            }
   }

有人可以帮忙吗?我真的不知道我犯了什么错误。我似乎没有关闭套接字,但我不知道为什么。

可能是我将套接字放在服务器端的队列中以便以某种方式复制套接字的问题吗?

编辑:如果我将客户端和服务器分别放在运行 Linux AMI 的不同 Amazon EC2 经典实例上,那么它可以工作。这可能是 Windows 的问题,还是仅仅是我在同一台机器(我的本地电脑)上运行客户端和服务器的问题?

有人看到我的代码中有错误吗?

Edit2:如上所述,它在 EC2 实例上有效,但如果我使用 netstat,它仍然显示很多行说 TIME_WAIT

以下是截图:

https://drive.google.com/file/d/0BzERdJrwWrNCWjhReGhpR2FBMUU/view?usp=sharing

https://drive.google.com/file/d/0BzERdJrwWrNCOG1TWGo5YmxlaTg/view?usp=sharing

第一个屏幕截图来自 Windows。 “WARTEND”的意思是“WAITING”(德语)。

第二个屏幕截图来自 Amazon EC2(左侧是客户端机器,右侧是服务器机器)。

【问题讨论】:

  • 只是一个想法——为什么不使用 RMI? RMI 处理套接字线程问题。
  • 不幸的是我不得不使用这种风格。
  • netstat 到底说了什么? “等待”不是港口状态。
  • @EJP 我已经更新了我的问题
  • 但是你还没有回答我的问题。 netstat 可以打印十几个状态,但“等待”不是其中之一。有几个名称中带有_WAIT。是哪个?

标签: java multithreading sockets


【解决方案1】:

TIME-WAIT 输入之后两端的连接都关闭。出于数据完整性原因,它会持续几分钟。

如果缓冲区问题是由于服务器的 TIME-WAIT 状态引起的,解决方案是让服务器成为最先收到关闭的对等方。这会将 TIME-WAIT 状态转移到客户端,它是良性的。

您可以通过将服务器端请求处理放入一个循环中来做到这一点,这样它就可以处理每个连接的多个请求,并且服务器只有在它到达流结束时才关闭套接字。

for (;;)
{
    try
    {
        ClientRequest clientRequest = (ClientRequest) inStream.readObject();
        ...
        outputStream.writeObject(serverResponse);
        outputStream.flush();
    }
    catch (EOFException exc)
    {
        break;
    }
}

如果你在客户端实现连接池,你将大大减少连接数,这将进一步减少缓冲区问题的发生率。

【讨论】:

  • 而你在德国 Windows 机器上的问题是你在同一台主机上运行服务器和客户端,并创建了无数的连接,这无论如何都不是一个现实的测试。
  • 客户端与服务器建立连接,收到响应后,关闭连接。然后建立一个新的连接等等......因此,我有很多连接。您的解决方案很好,但我不允许更改此设置(无连接池)。无论如何,服务器是否仍应等待流结束然后关闭?他只收到一个对象。时间路不能减少到1秒或更短吗?为什么客户端的时间等待状态是良性的?如果我在客户端等待的时间过长,客户端将无法创建新连接。
  • 由于我提到的原因,您仍然应该在服务器上实现循环。 TIME_WAIT 在客户端是良性的,因为它不会像在服务器上那样乘以客户端数量:它仅适用于客户端自己的连接。如果你真的想解决这个问题,你当然也应该实现连接池,你应该建议任何认为他们应该阻止你的人。
  • 谢谢,但我不知道服务器上的循环到底是什么意思。你能给出一些小的示例代码吗?客户端只发送一个对象,服务器发送一个应答但关闭连接。所以我每个连接没有几个请求。
  • 但是你应该像你那样对你的服务器进行编码,这就是重点。只是围绕请求/响应处理程序的一个循环,当EOFException 被捕获时终止。
猜你喜欢
  • 2013-08-22
  • 2011-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多