【问题标题】:PrintWriter very slow flush() and print(). Multithreads and socketsPrintWriter 非常慢的 flush() 和 print()。多线程和套接字
【发布时间】:2011-07-30 03:31:23
【问题描述】:

当我同时连接超过 500 个玩家时,我的(多线程)服务器出现了这个奇怪的问题,PrinterWriter 有时需要超过 100 秒或更长时间(2 分钟)才能完成 flush() 或 print()。

代码如下:

public static void send(Player p, String packet)
{   
    PrintWriter out = p.get_out();
    if(out != null && !packet.equals("") && !packet.equals(""+(char)0x00))
    {
        packet = Crypter.toUtf(packet);
        out.print((packet)+(char)0x00);
        out.flush();
    }
}

printWriter 是这样的:

_in = new BufferedReader(new InputStreamReader(_socket.getInputStream()));
_out = new PrintWriter(_socket.getOutputStream());

如果我在 send() 方法中添加关键字同步,整个服务器开始每 2 秒滞后一次,如果我不这样做,那么一些随机播放器会无缘无故开始滞后。

有人知道吗?这是从哪里来的?我该怎么办?

【问题讨论】:

  • 由于您无法控制客户端,因此您必须假设任意数量的客户端可能会停止阅读或速度慢到无法接受。发生这种情况时,您必须考虑如何处理。如果您的客户端读取数据的速度足够快,您应该能够在 10 毫秒内刷新到 500 个连接。即缓冲区总是有可用空间。您不能让一个慢速客户端拖慢其他所有客户端的速度。

标签: java multithreading sockets printwriter


【解决方案1】:

打印写入器包裹在套接字的输出流周围,所以我猜测套接字的输出缓冲区已满,因此 write/flush 调用将阻塞,直到缓冲区有足够的空间容纳消息被发送。

如果写入数据的速度快于传输到客户端的速度(或快于客户端接收数据的速度),则套接字发送缓冲区可能已满。

编辑:

附:如果您遇到可伸缩性问题,可能是由于使用了 java.io(每个套接字需要一个线程)而不是 java.nio(在这种情况下,单个线程可以检测并在那些具有待处理数据的套接字上执行操作) . nio 旨在支持必须扩展到大量连接的应用程序,但编程模型更加困难。

【讨论】:

  • 也许你是对的。我的默认缓冲区大小是:128 000 IN / 49 152 OUT。够了吗?多少才够?
  • 这与缓冲区大小无关,而与您写入套接字的速率以及客户端可以传输和接收数据的速率有关。如果第一个速率大于第二个,则调用者将始终阻塞/等待。在这种情况下,您可能会尝试太快地发送太多数据;降低更新速率或发送的数据量可能会有所帮助。
【解决方案2】:

原因是您的 send() 方法是静态的,因此写入任何套接字的所有线程都在包含的类对象上同步。使其成为非静态的,那么只有写入同一个套接字的线程才会被同步。

【讨论】:

  • 虽然该方法看起来像一个不共享任何资源的实用方法,所以似乎不需要同步。如果多个调用者可能同时操作一个 Player 实例,那么调用者可能应该负责在实用程序方法之外同步某个对象,例如 Player 实例本身。
  • 你是对的!谢谢!代码太大,我将不得不更改很多东西,但谢谢。如果只是线程问题,我希望它能解决问题。
猜你喜欢
  • 2018-02-28
  • 2011-02-11
  • 1970-01-01
  • 2016-03-16
  • 2013-01-19
  • 2012-09-07
  • 1970-01-01
  • 2017-08-10
  • 1970-01-01
相关资源
最近更新 更多