【问题标题】:Java: Sockets - DataStream really slowJava: Sockets - DataStream 真的很慢
【发布时间】:2012-05-05 11:16:03
【问题描述】:

我在线程中只使用普通的 DataInputStream 和 DataOutputStream 来接收、发送(在服务器上接受)来制作游戏,但它真的很慢。 >5 秒延迟。

这是我的制作方法(大部分看起来像这样):

(dos 是 DataOutputStream)

dos = new DataOutputStream(socket.getOutputStream());
dos.writeFloat(dp.x);
dos = new DataOutputStream(socket.getOutputStream());
dos.writeFloat(dp.y);
dos = new DataOutputStream(socket.getOutputStream());
dos.writeUTF(dp.username);

对于输入(这个在服务器中)我使用:

(dis 是 DataInputStream,它在 for 循环中,所以 i 代表每个播放器)

dis = new DataInputStream(list_sockets.get(i).getInputStream());
x = dis.readFloat();
dis = new DataInputStream(list_sockets.get(i).getInputStream());
y = dis.readFloat();
dis = new DataInputStream(list_sockets.get(i).getInputStream());
username = dis.readUTF();

所以它真的很慢,但我不知道为什么:( 请帮忙?

编辑:每个操作(发送、接受、接收)都有自己的守护线程。

【问题讨论】:

  • 为什么要反复创建新的 DataInput/OutputStreams?
  • 我不知道。这就是我看到其他人在网上做的方式。这是个大问题吗?
  • 这太浪费时间和资源了。
  • 好的,但是如果我只在开始时创建它,多人游戏会更快吗?
  • 没有人可以通过您发布的代码来判断。它不应该更慢,这就是所有可以说的。

标签: java performance sockets


【解决方案1】:

重复创建DataOutputStreamDataInputStream 实例不利于性能。

但是,我怀疑更重要的性能问题是您在没有任何 Java 端缓冲的情况下进行读写。这意味着每个读/写调用都在进行一个(可能还有很多)系统调用来读取数据。系统调用比普通的 Java 方法调用慢几个数量级。

您需要将 Socket 输入流包装在 BufferedInputStream 中,将输出流包装在 BufferedOutputStream 中,然后将它们包装在数据流中。 (请注意,当您这样做时,在每条消息或一系列消息的末尾flush DataOutputStream 变得更加重要。


我是否会写一些信息,然后在每次写入后刷新?

就像我上面所说的,您在每条消息或每个消息序列的末尾刷新。假设缓冲区中有要刷新的数据,缓冲输出流上的每次刷新都会导致系统调用。如果您在每次写入时都刷新,那么您(可能)正在执行不必要的系统调用。

由您决定协议的消息边界应该在哪里。这完全取决于您发送/接收的数据的详细信息以及处理方式。

【讨论】:

  • 噢噢噢!谢谢,所以 BufferedStream 对我不起作用,因为我没有刷新?
  • 我是先写一些信息,然后在每次写完后刷新或闪现吗?
  • (我不建议刷机。你可能会因此被捕 :-)
  • 我的意思是,几次后刷新,或者每次写入后刷新。大声笑
  • @IvanDonat 在请求/响应协议中,您实际上只需要在每次读取之前刷新。想想吧。
【解决方案2】:

就像您说的那样,您有一个 for 循环,并为循环中的每次迭代创建一个新的数据输入/输出流。这将导致巨大的开销。

您应该为每个客户端(在单独的线程上)有 1 个数据输入和输出流,然后通过循环构建输入的流来获取用户输入,直到输入流为空。

【讨论】:

    【解决方案3】:

    如果“慢”仅表示网络滞后,则应“刷新”流以强制传输非完整缓冲区。

    加法:

    即使这样你也会得到一个像这样的“工作草案”,考虑到一个设计良好的通信协议包含围绕简单命令的各种花里胡哨。问题出现

    • 异常处理
    • 测序
    • 身份验证
    • 完整性检查(避免作弊、重放……)
    • 可扩展性(新命令,使用显式命令对象)
    • 实时处理
    • 当然还有很多其他人...

    有一些框架可以帮助您摆脱这种负担。

    【讨论】:

    • 在每个“命令”完成后(例如,如果命令序列是三个整数,则在三个整数之后......)。
    • 我还是不明白。您能否编辑您的内容并添加一个编写一些整数或其他内容的示例以及将刷新放在哪里?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-11
    • 2013-04-12
    • 2018-09-19
    • 2012-02-03
    • 2017-11-10
    • 2010-12-28
    • 2013-01-25
    相关资源
    最近更新 更多