【问题标题】:How to write MappedByteBuffer to socket outputstream (server to client) with no copy如何在没有副本的情况下将 MappedByteBuffer 写入套接字输出流(服务器到客户端)
【发布时间】:2021-03-17 09:57:12
【问题描述】:

在 Java 代码中,我有一个使用 MappedByteBuffer 映射的文件区域,我需要将其发送到客户端(写入 Outputstream)。我需要确保在发送/写入套接字时,由于内存限制,它不会创建任何副本。我怎样才能做到这一点? Bytebuffer.array() 会达到这个目的吗?

分享代码。注意:FileChannel 是只读的,我需要按原样发送 ByteBuffer 数据。

private void writeData(Socket clientSocket, MappedByteBuffer byteBuffer){
    Path path = Paths.get(myfile);
    MappedByteBuffer memoryMappedBuffer = null;
        try (FileChannel fChannel = FileChannel.open(path, StandardOpenOption.READ)) {
            memoryMappedBuffer = fChannel.map(FileChannel.MapMode.READ_ONLY, location, size);
        }catch(){
        
    //How can i write memoryMappedBuffer to socket outputStream without copying data...? like
    clientSocket.getOutputStream().write(memoryMappedBuffer .array());
}

【问题讨论】:

    标签: java nio java-io virtual-memory memory-mapped-files


    【解决方案1】:

    如果您自己创建套接字,则可以改用SocketChannel.open(),而使用write(ByteBuffer)。它在内部管理套接字。

    InetSocketAddress address = ...
    SocketChannel channel = SocketChannel.open(address);
    channel.write(memoryMappedBuffer);
    // ...
    channel.close(); // Closes the connection
    

    如果你有一个预先存在的套接字,你可以从套接字的输出流创建一个Channel。但是,这会分配一个(重用的)临时缓冲区。

    WritableByteChannel channel = Channels.newChannel(clientSocket.getOutputStream());
    channel.write(memoryMappedBuffer);
    // ...
    channel.close();
    

    【讨论】:

      【解决方案2】:

      根据您的描述,您希望将文件的内容或文件的一部分写入套接字,将其映射到 Java 进程的虚拟地址空间。

      内存映射文件通常用于在多个进程之间共享内存,或者当您的进程向/从相同文件写入和读取数据时最小化磁盘上的 I/O 操作(一个具体的例子是 Kafka,它使用这个过程)。

      在您的情况下,当您将数据写入套接字时,该套接字有一个缓冲区(无论它是阻塞的还是非阻塞的)。当缓冲区已满时,您将无法写入,直到接收方确认数据并清除缓冲区。现在,如果接收器很慢,您将长时间保留加载到主内存的文件部分,这会影响服务器的性能(我想您的服务器不会有一个消费者/客户端) .

      一个好的和有效的解决方案是使用管道流,它以生产者/消费者的方式将数据从您的服务器发送到消费者(在本例中为套接字)。默认情况下,PipeInputStream 使用 1024 字节的缓冲区(您可以增加它),这意味着对于特定的执行线程,某一时刻只有 1024 字节将保留在内存中。如果您的进程有 500 个客户端,那么您将只消耗 500*1024 字节 = 512Kb。如果一个阅读器很慢,那么该生产者也会很慢,而不会对您的进程内存造成压力。

      如果你要做的只是将各种文件的内容写入套接字,我不知道使用内存映射文件对你有什么帮助。

      【讨论】:

        猜你喜欢
        • 2015-06-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-22
        • 1970-01-01
        • 2014-03-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多