如何在 Android 中创建命名管道 (mkfifo)?
我在 Android 中创建命名管道时遇到了麻烦,下面的示例说明了我的困境:
res = mkfifo("/sdcard/fifo9000", S_IRWXO);
if (res != 0)
{
LOG("Error while creating a pipe (return:%d, errno:%d)", res, errno);
}
代码总是打印:
Error while creating a pipe (return:-1, errno:1)
我无法弄清楚为什么会失败。该应用程序具有 android.permission.WRITE_EXTERNAL_STORAGE 权限。我可以在同一位置创建具有完全相同名称的普通文件,但管道创建失败。相关管道应该可以从多个应用程序访问。
- 我怀疑没有人可以在/sdcard 中创建管道。哪里是这样做的最佳地点?
- 我应该设置什么模式桅杆(第二个参数)?
- 应用程序是否需要任何额外的权限?
I am having trouble in creating named pipe in Android and the example below illustrates my dilemma:
res = mkfifo("/sdcard/fifo9000", S_IRWXO);
if (res != 0)
{
LOG("Error while creating a pipe (return:%d, errno:%d)", res, errno);
}
The code always prints:
Error while creating a pipe (return:-1, errno:1)
I can't figure out exactly why this fails. The application has android.permission.WRITE_EXTERNAL_STORAGE permissions. I can create normal files with exactly the same name in the same location, but pipe creation fails. The pipe in question should be accessible from multiple applications.
- I suspect that noone can create pipes in /sdcard. Where would it be the best location to do so?
- What mode mast should I set (2nd parameter)?
- Does application need any extra permissions?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
Roosmaa的答案是正确的——mkfifo()只是调用mknod()创建一个特殊文件,FAT32不支持那。
作为替代方案,您可能需要考虑使用 Linux 的“抽象命名空间”UNIX 域套接字。它们应该大致相当于命名管道。您可以通过名称访问它们,但它们不是文件系统的一部分,因此您不必处理各种权限问题。请注意,套接字是双向的。
由于它是一个套接字,因此您可能需要 INTERNET 权限。对此不太确定。
这是一些客户端/服务器示例代码:
Roosmaa's answer is correct -- mkfifo() just calls mknod() to create a special file, and FAT32 doesn't support that.
As an alternative you may want to consider using Linux's "abstract namespace" UNIX-domain sockets. They should be roughly equivalent to a named pipe. You can access them by name, but they're not part of the filesystem, so you don't have to deal with various permission issues. Note the socket is bi-directional.
Since it's a socket, you may need INTERNET permission. Not sure about that.
Here's a quick bit of client/server sample code:
/sdcard的默认文件系统是FAT32,不支持命名管道。
在非 root 设备上,您可以尝试创建这些管道的唯一可能的位置是应用程序数据目录 /data/data/com.example/ 。
注意:您不应对该值进行硬编码,应使用 Context.getApplicationInfo().dataDir 。
但请注意,每当用户使用 Apps2SD 或每当 Google 正式实施该支持时,您都需要确保让用户知道该应用程序无法存储在 vfat 文件系统上。
The default filesystem of /sdcard is FAT32, which doesn't support named pipes.
On a non-rooted device the only possible place you could try to create those pipes would be the application data directory /data/data/com.example/ .
Note: You shouldn't hardcode that value, use the Context.getApplicationInfo().dataDir .
But be aware that whenever the user is using Apps2SD or whenever Google implements that support officially you need to make sure to let the user know that the app can't be stored on vfat files system.
还有
/sqlite_stmt_journals
(我们用它来测试,我不知道这个目录在操作系统更新后能存活多久)如果你需要 IPC,最好的做法是使用 Binders
如果你只需要线程间通信,你可以通过 JNI 使用无名管道(这样可以美好的)
there's also
/sqlite_stmt_journals
(we use it for testing, I don't know how long this directory will survive OS updates)If you need IPC, the best practices are to use the Binders
If you only need inter-thread communication, you can use unnamed pipes through JNI (this works fine)
我想附加到已接受的答案:
1)我可以使用此方法在 Android 应用程序的两个本机模块之间连接套接字。
2) write() 应该处于循环中,因为它可能无法写入第一次写入请求的全部数量。例如,它应该是这样的:
上面显示的错误处理是不够的,因为几个错误代码只是指示重试。请参阅 write 的文档。
I would like to append to the accepted answer:
1) I am able to use this method to connect a socket between two native modules of an Android app.
2)
write()
should be in a loop since it may not write the full amount requested in the first go. For example, it should read something like:The error handling shown above is insufficient, since several error codes simply indicate to try again. See the documentation for write.
如果您使用 Java 进行编码,则应该使用 PipedInputStream和 PipedOutputStream。
If you're coding this in Java, you should just use PipedInputStream and PipedOutputStream.