Как создать именованный канал (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.разрешение.Разрешения write_external_storage по. Я могу создать обычные файлы с точно таким же именем в том же месте, но создание канала не удается. Рассматриваемая труба должна быть доступна из нескольких приложения.
- Я подозреваю, что никто не может создать трубы в /sdcard. Где это было бы лучшим местом для этого?
- какой режим мачты я должен установить (2-й параметр)?
- требуется ли приложению какие-либо дополнительные разрешения?
5 ответов
ответ Roosmaa правильно -- mkfifo () просто вызывает mknod () для создания специального файла, и FAT32 не поддерживает это.
в качестве альтернативы вы можете рассмотреть возможность использования "абстрактного пространства имен" UNIX-domain сокетов 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] = ''; /* 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;
}
файловой системой по умолчанию /sdcard является FAT32, которая не поддерживает именованные каналы.
на некорневом устройстве единственным возможным местом, где вы можете попытаться создать эти каналы, будет каталог данных приложения /data/data / com.образец. / Примечание: Вы не должны жестко закодировать значение, используйте контекст.getApplicationInfo().переменной datadir .
но имейте в виду, что всякий раз, когда пользователь использует Apps2SD или когда Google реализует эту поддержку официально, вам нужно убедиться, что пользователь знает, что приложение не может быть сохранено в файловой системе vfat.
там же /sqlite_stmt_journals
(мы используем его для тестирования, я не знаю, как долго этот каталог выживет обновления ОС)
Если вам нужен IPC, рекомендуется использовать биндеры
Если вам нужна только связь между потоками, вы можете использовать неназванные каналы через JNI (это отлично работает)
Я хотел бы добавить к принято отвечать:
1) я могу использовать этот метод для подключения сокета между двумя собственными модулями приложения для Android.
2) write()
должен быть в цикле, так как он не может написать полную сумму, запрошенную на первом ходу. Например, он должен читать что-то вроде:
void *p = buffer;
count = 0;
while ((count += write(clientSock, buffer, num_bytes - count)) < num_bytes)
{
if (count < 0)
{
close(clientSock);
errCode = count;
break;
}
p += count;
}
обработка ошибок, показанная выше, недостаточна, так как несколько кодов ошибок просто указывают на повторную попытку. См. документацию написать.
Если вы кодируете это на Java, вы должны просто использовать PipedInputStream и PipedOutputStream.