【问题标题】:ObjectOutputStream writeObject hangs when two clients send objects to server当两个客户端向服务器发送对象时,ObjectOutputStream writeObject 挂起
【发布时间】:2016-10-18 12:22:35
【问题描述】:

我正在编写客户端/服务器应用程序,其中多个客户端连接到服务器并通过 TCP 连接以高速率连续向服务器发送序列化对象。

我在客户端使用 ObjectOutputStream.writeObject,在服务器使用 ObjectInputStream.readObject。

服务器应用程序使用 serverSocket.accept() 在单个端口上接受客户端连接,并将 Socket 传递给新线程以读取对象。

当单个客户端连接并发送大约 25K 个对象/秒时 - 一切正常。一旦我启动第二个客户端,在很短的时间之后,一个或两个客户端都挂在其中一台服务器的 ObjectOutputStream.writeObject 上,而相应的服务器挂起在 ObjectInputStream.readObject 上。 双方都没有抛出异常。

如果速率非常低,假设总共 10-20/s - 它不会挂起,但在 100-1000/s 时会挂起。

在客户端机器上使用netstat -an可以看到对应链接的send-Q大概有30K左右。在服务器端,receive-Q 也是 ~30K。

在本地 Windows 上运行客户端/服务器时,我观察到类似的情况 - 客户端挂起,但服务器继续处理传入的对象,一旦赶上,客户端解锁并继续发送对象。

在本地,在 windows 上,服务器比客户端慢,但在 linux 上,运行在不同机器上的服务器实例数量足以满足客户端产生的速度。

有什么线索吗?

客户端代码片段:

Socket socket = new Socket(address, port);
ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream());
while(true)
{
     IMessage msg = createMsg();
     outputStream.writeObject(msg);
     outputStream.flush();
     outputStream.reset();
}

接受连接的服务器代码:

while(active)
{
    Socket socket = serverSocket.accept();
    SocketThread socketThread = new SocketThread(socket);
    socketThread.setDaemon(true);
    socketThread.start();
}

服务器代码读取对象:

public class SocketThread extends Thread 
    {
        Socket socket;
        public SocketThread(Socket socket)
        {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                ObjectInputStream inStream = new ObjectInputStream(socket.getInputStream());
                while(true)
                {
                    IMessage msg = (IMessage)inStream.readObject();
                    if(msg == null){
                        continue;
                    }
                    List<IMessageHandler> handlers = handlersMap.get(msg.getClass());
                    for(IMessageHandler handler : handlers){
                        handler.onMessage(msg);
                    }
                }
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

【问题讨论】:

  • NB readObject() 不会返回 null,除非您发送 null。如果您不打算这样做,那么空测试毫无意义。

标签: java sockets tcp objectinputstream objectoutputstream


【解决方案1】:

您刚刚描述了发送方超过接收方时 TCP 的操作。接收方告诉发送方停止发送,所以发送方停止发送。当您使用阻塞 I/O 时,客户端会在内部阻塞 send()

这里没有问题要解决。

【讨论】:

  • 不,它没有。服务器愉快地使用单个客户端处理 25K/s,但使用两个客户端冻结在 1K/s。
  • 所以你在服务器上有并发问题。
【解决方案2】:

问题是服务器端的处理程序使用了一些非线程安全的资源(如 Jedis 连接),所以它都是服务器端的堆栈。

线程安全解决了这个问题。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2023-03-25
  • 2014-10-08
  • 1970-01-01
  • 2018-09-22
  • 2017-07-10
  • 1970-01-01
  • 2015-06-15
  • 2014-10-07
相关资源
最近更新 更多