当两个客户端向服务器发送对象时,ObjectOutputStream writeObject 挂起
Posted
技术标签:
【中文标题】当两个客户端向服务器发送对象时,ObjectOutputStream writeObject 挂起【英文标题】:ObjectOutputStream writeObject hangs when two clients send objects to server 【发布时间】: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();
【问题讨论】:
NBreadObject()
不会返回 null,除非您发送 null。如果您不打算这样做,那么空测试毫无意义。
【参考方案1】:
您刚刚描述了发送方超过接收方时 TCP 的操作。接收方告诉发送方停止发送,所以发送方停止发送。当您使用阻塞 I/O 时,客户端会在内部阻塞 send()
。
这里没有问题要解决。
【讨论】:
不,它没有。服务器愉快地使用单个客户端处理 25K/s,但使用两个客户端冻结在 1K/s。 所以你在服务器上有并发问题。【参考方案2】:问题是服务器端的处理程序使用了一些非线程安全的资源(如 Jedis 连接),所以它都是服务器端的堆栈。
线程安全解决了这个问题。
【讨论】:
所以你在服务器上遇到了并发问题,正如我在 21 个月前所说的那样。 那你为什么要告诉我们一些我在 21 个月前已经告诉过你的事情? 为你找到了一些可以讨论这个的论坛socialanxietysupport.com/forum/f24/human-behaviour-2122330/#/…以上是关于当两个客户端向服务器发送对象时,ObjectOutputStream writeObject 挂起的主要内容,如果未能解决你的问题,请参考以下文章