如何将mappedbytebuffer写入socket outputstream(服务器到客户机)而不复制

jq6vz3qz  于 2021-07-03  发布在  Java
关注(0)|答案(2)|浏览(455)

在java代码中,我使用mappedbytebufferMap了一个文件区域,需要将其发送到客户机(写入outputstream)。我需要确保在发送/写入socket时,由于内存限制,它不会创建任何副本。我怎样才能做到这一点?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());
}
chy5wohz

chy5wohz1#

如果您自己创建套接字,可以使用 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();
ogsagwnx

ogsagwnx2#

根据您的描述,您希望将文件的内容或文件的一个片段写入套接字,该片段将Map到java进程的虚拟地址空间。
内存Map文件通常用于在多个进程之间共享内存,或者在进程向同一文件写入数据或从同一文件中读取数据时最小化磁盘上的i/o操作(一个具体的示例是kafka,它使用此过程)。
在您的例子中,当您将数据写入套接字时,该套接字有一个缓冲区(不管它是阻塞的还是非阻塞的)。当缓冲区满了,你将不能写,直到接收器确认数据,缓冲区被清除。现在,如果接收器速度慢,您将长时间保留加载到主内存中的文件部分,这可能会影响服务器的性能(我假设您的服务器没有一个使用者/客户机)。
一个好而有效的解决方案是使用管道流,它以生产者/消费者的方式将数据从服务器发送到消费者(在本例中是套接字)。默认情况下,pipeinputstream使用1024字节的缓冲区(您可以增加它),这意味着对于特定的执行线程,在同一时刻内存中只保留1024字节。如果您的进程有500个客户端,那么您将只消耗500*1024字节=512kb。如果一个读卡器很慢,那么这个生产者也会很慢,而不会给进程内存带来压力。
如果您所要做的只是将各种文件的内容写入套接字,我不知道如何使用内存Map文件来帮助您。

相关问题