使用 IOUtils.copy() 时套接字流挂起

发布于 2024-10-05 14:16:38 字数 986 浏览 5 评论 0原文

我想将包含 XML 的 InputStream 从客户端发送到服务器。所述服务器使用Streaming API for XML (StAX)操作XML流并将其发送回客户端。

我设法将 XML 发送到服务器,客户端收到答案,但不会退出,因为服务器永远不会完成从客户端读取 InputStream 。 但是,当服务器只是将输入转储到 System.out 而不是发送某些内容时,读取就完成了...

编辑我忘了提及这一点IOUtils.copy() 在客户端上的两个单独线程中运行。

这里有一些代码可以重现这一点,我在服务器上用 IOUtils.copy() 替换了 StAX 部分。

服务器

ServerSocket serverSocket = new ServerSocket(port);
Socket clientSocket = serverSocket.accept();

InputStream in = clientSocket.getInputStream();
OutputStream out = clientSocket.getOutputStream();
IOUtils.copy(in, out);

客户端

Socket socket = new Socket(host, port);
FileInputStream fin = new FileInputStream(file);
OutputStream out = socket.getOutputStream();
IOUtils.copy(fin, out)

InputStream in = socket.getInputStream();
IOUtils.copy(in, System.out)

I want to send an InputStream containing XML from the client to a server. Said server manipulates the XML stream using Streaming API for XML (StAX) and sends it back to the client.

I mange to send the XML to the server, the client receives the answer, but doesn't exit because the server never finishes reading the InputStream form the client.
But when the server is just dumping the input to System.out instead of sending something, reading finishes...

edit I forgot to mention that IOUtils.copy() is running in two separate threads on the client.

Here some code to reproduce this, I've replaced the StAX part with IOUtils.copy() on the server.

Server

ServerSocket serverSocket = new ServerSocket(port);
Socket clientSocket = serverSocket.accept();

InputStream in = clientSocket.getInputStream();
OutputStream out = clientSocket.getOutputStream();
IOUtils.copy(in, out);

Client

Socket socket = new Socket(host, port);
FileInputStream fin = new FileInputStream(file);
OutputStream out = socket.getOutputStream();
IOUtils.copy(fin, out)

InputStream in = socket.getInputStream();
IOUtils.copy(in, System.out)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

从来不烧饼 2024-10-12 14:16:39

您必须刷新并关闭InputStream 和OutputStream。
像这样:

ServerSocket serverSocket = new ServerSocket(port);
Socket clientSocket = serverSocket.accept();

InputStream in = clientSocket.getInputStream();
OutputStream out = clientSocket.getOutputStream();
IOUtils.copy(in, out);

//add 
out.flush();
in.close();
out.close;

You must flush and close InputStream and OutputStream.
like this:

ServerSocket serverSocket = new ServerSocket(port);
Socket clientSocket = serverSocket.accept();

InputStream in = clientSocket.getInputStream();
OutputStream out = clientSocket.getOutputStream();
IOUtils.copy(in, out);

//add 
out.flush();
in.close();
out.close;
冷︶言冷语的世界 2024-10-12 14:16:39

您可能正在造成僵局。

  • 客户端 - 将数据发送到服务器。
  • 服务器 - 将数据循环回客户端。
  • 客户端 - 读取数据(服务器环回)

因此,当客户端将数据发送到服务器时,服务器将其发送回客户端。
客户端没有读取该数据,而是正忙于发送。

在某些时候,TCP 缓冲区会填满,服务器会阻止向客户端发送更多数据。这意味着服务器在发送数据时被阻止,因此最终服务器接收端的 TCP 缓冲区也被填满,并且客户端在发送数据时被阻止。由于客户端现在在发送时被阻止,因此它永远不会到达读取环回数据的部分,因此服务器永远不会解除阻止。

如果您发送一个小文档,您可能不会遇到这种情况,因为所有数据都适合缓冲区,但是一旦填满缓冲区,系统就会死锁。

您必须复用发送/接收。例如,您可以在客户端上启动一个线程,

InputStream in = socket.getInputStream();
IOUtils.copy(in, System.out)

这样接收数据可以与客户端发送数据并行完成

,或者您可以在服务器端使用 2 个线程。一个用于接收数据,将要发送回的数据发送回另一个执行发送的线程(在这种情况下,您必须在线程之间建立一个内部队列)。

You are probably creating a deadlock.

  • Client - sends data to the server.
  • Server - loops data back to the client.
  • Client - reads data (that the server looped back)

So, while the client is sending data to the server, the server is sending it back to the client.
The client isn't reading that data, it's busy sending.

At some point the TCP buffers fill up, and the server blocks on sending more data to the client. This means the server is blocked on sending data, so eventually the TCP buffers on the receiving side of the server fills up as well, and the client blocks on sending data. Since the client is now blocked on sending, it'll never get to the part where it reads the data that is looped back, so the server will never un-block.

If you're sending a small document, you might not experience this, as all the data fits in the buffers, but once you fill up the buffers, the system will deadlock.

You have to multiplex the sending/receiving. e.g. you could start up a thread on the client that does

InputStream in = socket.getInputStream();
IOUtils.copy(in, System.out)

That way receiving can be done in parallel with the client sending data

Or you could use 2 threads on the server side. One for receiving the data, posting data to be sent back to another thread doing the sending (you'll have to build up an internal queue in this case between the threads).

清风夜微凉 2024-10-12 14:16:39

据我记得 IOUtils.copy() 不会刷新并且不会关闭流。看来你也没有调用“flush”或“close”。尝试一下。我相信这是你的问题。

As far as I remember IOUtils.copy() does not flush and does not close the stream. It seems that you do not call neither flush nor close too. Try it. I believe that this is your problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文