15

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 権限があります。同じ場所にまったく同じ名前の通常のファイルを作成できますが、パイプの作成に失敗します。問題のパイプは、複数のアプリケーションからアクセスできる必要があります。

  1. /sdcard にパイプを作成できる人はいないと思います。そうするのに最適な場所はどこですか?
  2. どのモード マストを設定すればよいですか (2 番目のパラメーター)?
  3. アプリケーションには追加のアクセス許可が必要ですか?
4

5 に答える 5

18

Roosmaa の答えは正しいです。mkfifo() は mknod() を呼び出して特別なファイルを作成するだけで、FAT32 はそれをサポートしていません。

別の方法として、Linux の「抽象名前空間」UNIX ドメイン ソケットの使用を検討することもできます。それらは、名前付きパイプとほぼ同等である必要があります。名前でアクセスできますが、ファイルシステムの一部ではないため、さまざまな権限の問題に対処する必要はありません。ソケットは双方向であることに注意してください。

これはソケットなので、INTERNET パーミッションが必要になる場合があります。それについてはわかりません。

以下は、クライアント/サーバーのサンプル コードの一部です。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stddef.h>
#include <sys/socket.h>
#include <sys/un.h>

/*
 * Create a UNIX-domain socket address in the Linux "abstract namespace".
 *
 * The socket code doesn't require null termination on the filename, but
 * we do it anyway so string functions work.
 */
int makeAddr(const char* name, struct sockaddr_un* pAddr, socklen_t* pSockLen)
{
    int nameLen = strlen(name);
    if (nameLen >= (int) sizeof(pAddr->sun_path) -1)  /* too long? */
        return -1;
    pAddr->sun_path[0] = '\0';  /* abstract namespace */
    strcpy(pAddr->sun_path+1, name);
    pAddr->sun_family = AF_LOCAL;
    *pSockLen = 1 + nameLen + offsetof(struct sockaddr_un, sun_path);
    return 0;
}

int main(int argc, char** argv)
{
    static const char* message = "hello, world!";
    struct sockaddr_un sockAddr;
    socklen_t sockLen;
    int result = 1;

    if (argc != 2 || (argv[1][0] != 'c' && argv[1][0] != 's')) {
        printf("Usage: {c|s}\n");
        return 2;
    }

    if (makeAddr("com.whoever.xfer", &sockAddr, &sockLen) < 0)
        return 1;
    int fd = socket(AF_LOCAL, SOCK_STREAM, PF_UNIX);
    if (fd < 0) {
        perror("client socket()");
        return 1;
    }

    if (argv[1][0] == 'c') {
        printf("CLIENT %s\n", sockAddr.sun_path+1);

        if (connect(fd, (const struct sockaddr*) &sockAddr, sockLen) < 0) {
            perror("client connect()");
            goto bail;
        }
        if (write(fd, message, strlen(message)+1) < 0) {
            perror("client write()");
            goto bail;
        }
    } else if (argv[1][0] == 's') {
        printf("SERVER %s\n", sockAddr.sun_path+1);
        if (bind(fd, (const struct sockaddr*) &sockAddr, sockLen) < 0) {
            perror("server bind()");
            goto bail;
        }
        if (listen(fd, 5) < 0) {
            perror("server listen()");
            goto bail;
        }
        int clientSock = accept(fd, NULL, NULL);
        if (clientSock < 0) {
            perror("server accept");
            goto bail;
        }
        char buf[64];
        int count = read(clientSock, buf, sizeof(buf));
        close(clientSock);
        if (count < 0) {
            perror("server read");
            goto bail;
        }
        printf("GOT: '%s'\n", buf);
    }
    result = 0;

bail:
    close(fd);
    return result;
}
于 2010-05-03T18:28:41.573 に答える
8

/sdcard のデフォルトのファイルシステムは FAT32 で、名前付きパイプをサポートしていません。

ルート化されていないデバイスでは、これらのパイプを作成できる唯一の可能な場所は、アプリケーション データ ディレクトリ /data/data/com.example/ です。注: その値をハードコーディングしないでください。 Context.getApplicationInfo().dataDir を使用してください。

ただし、ユーザーが Apps2SD を使用している場合、または Google がそのサポートを公式に実装している場合は常に、アプリを vfat ファイル システムに保存できないことをユーザーに知らせる必要があることに注意してください。

于 2010-05-03T12:42:03.873 に答える
1

もあります/sqlite_stmt_journals(テストに使用します。このディレクトリがOSの更新にどれだけ存続するかはわかりません)

IPC が必要な場合のベスト プラクティスは、バインダーを使用することです。

スレッド間通信のみが必要な場合は、JNI を介して名前のないパイプを使用できます (これは正常に機能します)。

于 2010-05-07T09:58:05.317 に答える
-1

これを Java でコーディングしている場合は、PipedInputStreamPipedOutputStreamを使用する必要があります。

于 2010-05-08T08:59:25.603 に答える