创建一个内存中的FileDescriptor [英] Create an in-memory FileDescriptor

查看:100
本文介绍了创建一个内存中的FileDescriptor的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

FileDescriptor API:

文件描述符类的实例用作不透明句柄表示打开文件的基础机器特定结构,一个开放的套接字,或另一个字节的源或宿.

Instances of the file descriptor class serve as an opaque handle to the underlying machine-specific structure representing an open file, an open socket, or another source or sink of bytes.

我想使用 ByteArrayOutputStream ByteArrayInputStream

此外,FileDescriptor是最终类,不能被覆盖.唯一的构造函数说-

Also, FileDescriptor is a final class and cannot be overridden. The only constructor it has says -

构造一个(无效) FileDescriptor对象.

Constructs an (invalid) FileDescriptor object.

有什么想法如何在Android中使用FileDescriptor?

Any idea how to use FileDescriptor in Android?

EDIT

EDIT

我想在

I want to use it in MediaMuxer. Instead of writing to a file, I want to have the media data in-memory and copy it to a TCP socket for live streaming. So my FileDescriptor should be a "sink of bytes."

推荐答案

使用 LocalSocket ,但要小心,因为会涉及安全性.

Use a LocalSocket, but be careful because there are security implications.

LocalSocket 是用于Unix域套接字的Android API.域套接字与TCP/IP套接字类似,不同之处在于它们仅存在于设备上,不能用于通过网络的通信.

LocalSocket is the Android API for working with Unix Domain Sockets. Domain Sockets are similar to TCP/IP sockets except that they only exist on the device, they cannot be used for communication across a network.

一个简单但不安全的解决方案如下:

A simple, but insecure solution to your problem is as follows:

// Create a unique name for the socket.
String name = "your.package.name-" + UUID.randomUUID();

// Bind a server to the socket.
final LocalServerSocket server = new LocalServerSocket(name);

// Connect a client to the socket.
LocalSocket client = new LocalSocket(LocalSocket.SOCKET_STREAM);
client.connect(new LocalSocketAddress(name, LocalSocketAddress.Namespace.ABSTRACT));

// Start a thread to read from the server socket.
new Thread(new Runnable {
    @Override
    public void run() {
        LocalSocket socket = server.accept();

        // To read data sent by the client, read from socket.getInputStream().
        // To send data to the client, write to socket.getOutputStream().

        // After you are done you will need to call socket.close().
    }
}).start();

// Get the FileDescriptor associated with the client.
// You can use this FileDescriptor to write data to and/or read data
// sent from the server.
FileDescriptor fileDescriptor = client.getFileDescriptor();

// After you are done you will need to call server.close() and client.close().

这将在抽象套接字名称空间中创建一个套接字.这是不安全的,因为域套接字是系统范围的,并且抽象名称空间中的套接字不受任何权限系统的限制.连接或绑定到抽象名称空间中的名称的唯一要求是知道名称,并且攻击者可以通过反编译轻松发现应用程序使用的套接字名称.另外,另一个应用程序可能会偶然使用相同的套接字名称.因此,另一个应用程序可能会拦截您的数据,或通过套接字发送意外的数据,因此很难防范.

This creates a socket in the abstract socket namespace. This is insecure because domain sockets are system-wide and sockets in the abstract namespace are not restricted by any permissions system. The only requirement to connect or bind to a name in the abstract namespace is to know the name, and the socket name used by your app can be easily discovered by an attacker through decompilation. There is also a possibility that another app may use the same socket name by accident. So another app could intercept your data, or send unexpected data through the socket, and it is difficult to guard against this.

一种更好但更复杂的解决方案是在文件系统名称空间中创建一个套接字.用于执行此操作的API非常奇怪,但是可以通过以下方式实现:

A better, but more complicated solution is to create a socket in the filesystem namespace. The API to do this is super weird, but it can be achieved as follows:

// Create a unique name for the socket in your app's private data area.
// Note this example creates a file named like socket-xxxx in the root of
// your app's private data area. You might want to put it in a subdirectory.
String name = context
    .getFileStreamPath("socket-" + UUID.randomUUID())
    .getAbsolutePath();
LocalSocketAddress address = new LocalSocketAddress(name, LocalSocketAddress.Namespace.FILESYSTEM);

// Bind a server to the socket.
LocalSocket server = new LocalSocket(LocalSocket.SOCKET_STREAM);
server.bind(address);
final LocalServerSocket serverWrapper = new LocalServerSocket(server.getFileDescriptor());

// Connect a client to the socket.
LocalSocket client = new LocalSocket(LocalSocket.SOCKET_STREAM);
client.connect(address);

// Start a thread to read from the server socket.
new Thread(new Runnable {
    @Override
    public void run() {
        LocalSocket socket = serverWrapper.accept();

        // To read data sent by the client, read from socket.getInputStream().
        // To send data to the client, write to socket.getOutputStream().

        // After you are done you will need to call socket.close() and
        // serverWrapper.close().
    }
}).start();

// Get the FileDescriptor associated with the client.
// You can use this FileDescriptor to write data to and/or read data
// sent from the server.
FileDescriptor fileDescriptor = client.getFileDescriptor();

// After you are done you will need to call server.close() and client.close().

这确实在文件系统上创建了一个文件,但是没有任何将通过套接字的数据写入磁盘,而是完全在内存中.该文件只是代表套接字的名称,类似于/dev 中代表设备的文件.由于套接字是通过文件系统访问的,因此必须遵守通常的文件系统权限,因此可以通过将套接字放置在应用程序的私有数据区域中来限制对套接字的访问.

This does create a file on the filesystem, but none of the data that passes through the socket is ever written to disk, it is entirely in-memory. The file is just a name that represents the socket, similar to the files in /dev that represent devices. Because the socket is accessed through the filesystem, it is subject to the usual filesystem permissions, so it is easy to restrict access to the socket by placing the socket in your app's private data area.

由于此技术会在文件系统上创建文件,因此最好在完成后删除该文件,并且还可能经常检查和清理旧的套接字,以防应用程序崩溃和崩溃.留下旧文件.

Since this technique creates a file on the filesystem, it would be a good idea to delete the file after you're done, and also perhaps to check for and clean up old sockets every so often, in case your app crashes and leaves old files laying around.

这篇关于创建一个内存中的FileDescriptor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆