Как создать именованный канал (mkfifo) в Android?

Я испытываю затруднения создать именованный канал в 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. Для приложения нужны какие-либо дополнительные полномочия?
12
задан moala 17 January 2012 в 13:13
поделиться

4 ответа

Ответ Роосмаа правильный - mkfifo () просто вызывает mknod () для создания специального файла, а FAT32 не поддерживает это.

В качестве альтернативы вы можете рассмотреть возможность использования сокетов UNIX-домена Linux «абстрактного пространства имен». Они должны быть примерно эквивалентны именованному каналу. Вы можете получить к ним доступ по имени, но они не являются частью файловой системы, поэтому вам не нужно решать различные проблемы с разрешениями. Обратите внимание, что розетка двунаправленная.

Поскольку это сокет, вам может потребоваться разрешение в ИНТЕРНЕТЕ. Не уверен в этом.

Вот небольшой пример кода клиент / сервер:

#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;
}
15
ответ дан 2 December 2019 в 06:26
поделиться

Файловая система / sdcard по умолчанию - FAT32, которая не поддерживает именованные каналы.

На устройстве без рутирования единственное возможное место, где вы могли бы попытаться создать эти каналы, - это каталог данных приложения /data/data/com.example/. Примечание: вам не следует жестко кодировать это значение используйте Context.getApplicationInfo (). dataDir.

Но имейте в виду, что всякий раз, когда пользователь использует Apps2SD или когда Google официально реализует эту поддержку, вы должны обязательно сообщить пользователю, что приложение не может быть сохранено в файловой системе vfat.

8
ответ дан 2 December 2019 в 06:26
поделиться

Есть еще /sqlite_stmt_journals (мы используем его для тестирования, я не знаю, как долго этот каталог переживет обновления ОС)

Если вам нужен IPC, лучше всего использовать Binders

Если вам нужно только межпоточное взаимодействие, вы можете использовать неименованные трубы через JNI (это отлично работает)

1
ответ дан 2 December 2019 в 06:26
поделиться

Если вы кодируете это на Java, вам следует просто использовать PipedInputStream и PipedOutputStream .

-1
ответ дан 2 December 2019 в 06:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: