【问题标题】:How to send very large objects over socket如何通过套接字发送非常大的对象
【发布时间】:2017-09-22 13:59:25
【问题描述】:

我的系统涉及通过 TCP 套接字发送大量数据和元数据。我正在发送一个包含各种元数据以及 20 个字节数组的对象。到目前为止,我一直在使用包含 BufferedOutputStream 的 ObjectOutputStream 来处理小示例(130kB 数组)。我尝试达到 67MB 数组的目标,但 ObjectOutputStream 无法处理那么多数据。我能够发送 1MB 的数组,但是 writeObject() 在 2MB 时挂断了。

我听说 DataOutputStream 更快,但我宁愿不必将我的元数据编码为字节并在另一端解码。有没有一个可以快速发送非常大的对象的好方法?

编辑:

我已经在每个 write 方法之后使用了 reset()。我目前正在发送一个包含我自己的 Message 对象的 SignedObject,该对象包含 20 个数组以及许多元数据字段。我宁愿把这一切都打包,因为它很方便,但我知道分离可能是唯一的方法。话虽如此,我仍然需要确保所有传输都是安全的。

更新:

所以我去吃午饭,回来后决定尝试弄清楚事情是挂在发送端还是接收端。然后它就再也没有挂断。我可以继续成功发送多达 4MB 的数组,直到我用完堆(这是不相关的,只是意味着我需要一台更好的计算机或更有效的处理)。所以我想问题消失了?但这并不意味着我不需要更好的传播方式,所以如果人们有想法,我会采取更多的想法。另外,我假设一旦我更新它,它将再次停止工作......

【问题讨论】:

  • 用量子物理瞬间发送? :-) 或者用无聊的方式来做:压缩
  • 您真的期望 60MB 的数据传输会立即发生吗?不管你怎么做(除非你可以压缩或消除它的大部分),它都会相对缓慢。这就是为什么我们没有可以从互联网等启动的计算机的部分原因。
  • “太慢了”因为它无限期地挂起。为澄清而编辑
  • 如果您的代码挂起,那么您就有了错误。我已经使用 ObjectOutputStream 发送 GB 的数据而没有问题。虽然协议可能有点冗长,但它不会挂起。至于冗长,如果您要发送大量数据,我怀疑 OOS 开销会很重要。
  • @jtahlborn:如果挂了,那么问题可能出在接收端吗?

标签: java sockets large-data


【解决方案1】:

有没有一个很好的替代方法可以快速发送非常大的对象?

在发送的对象之间使用带有 reset() 的 ObjectOutputStream。除非您只有几 MB 内存(在这种情况下您应该获得更多),否则您不会有问题。

与自己编码字节相比,ObjectOutputStream 相当慢,但它可以很好地处理编码。您的网络上传速度更有可能是您的限制因素。在这个例子中,它发送大约 600 Mb/s,而大多数宽带连接大约是 500 kb/s(大约慢 1000 倍)

ServerSocket ss = new ServerSocket(0);
Socket s = new Socket("localhost", ss.getLocalPort());
final Socket s2 = ss.accept();
ss.close();

new Thread(new Runnable() {
    @Override
    public void run() {
        int count = 0;
        long start = System.nanoTime();
        try {
            ObjectInputStream in = new ObjectInputStream(
                    new InflaterInputStream(s2.getInputStream()));
            while (in.readObject() != null) count++;
            s2.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        long time = System.nanoTime() - start;
        System.out.printf("Read %,d objects in %.3f seconds%n", count, time / 1e9);
    }
}, "reader").start();
ObjectOutputStream oos = new ObjectOutputStream(
        new DeflaterOutputStream(s.getOutputStream()));
for (int i = 0; i < 20; i++) {
    byte[] bytes = new byte[67 * 1000 * 1000];
    oos.writeObject(bytes);
    oos.reset();
}
oos.writeObject(null); // poison pill
oos.close();
s.close();

打印

Read 20 objects in 21.644 seconds

【讨论】:

  • 听起来 OP 正在发送一个大对象,因此 reset 在这种情况下可能无法使用。
  • @jtahlborn OP 说 2 MB 对象失败。很难看出只有 2 MB 怎么可能太多了。必须有数百个才会导致问题。
猜你喜欢
  • 2012-03-13
  • 2013-09-02
  • 2019-04-21
  • 2014-01-11
  • 2022-01-15
  • 2021-01-11
  • 2014-03-24
相关资源
最近更新 更多