Опрос () по именованной трубе возвращается с POLLHUP постоянно и немедленно
Я открываю именованный канал (fifo, созданный mkfifo) с неблокирующим флагом (open(...O_NONBLOCK)), затем начинаю опрос (poll(...)). Все идет нормально. Затем из командной строки я делаю пару
echo 123 > /tmp/fifo
Все они считываются из канала, как и ожидалось (по крайней мере, я ожидаю, что именно так они должны работать в обычном режиме).
Моя проблема в том, что после первого эха, POLLHUP установлен, и он застрял, опрос немедленно возвращается с этой точки.
Как мне очистить / избавиться от POLLHUP?
Это начинает сводить меня с ума:(
Да, другой конец трубы был закрыт (после того, как он был открыт ранее), поэтому он стал наполовину закрытым, но мой конец все еще открыт и жив, и мне так нравится. Он не мертвый, я все еще могу получать новые эхо через канал, это просто опрос, опрашивающий реку POLLHUP (которую я даже не запрашивал в первую очередь в событиях, но опрос может просто пометить их в любом случае [man poll: "В число местностей могут входить любые из указанных в событиях или одно из значений POLLERR, POLLHUP"]), и из-за этого они практически бесполезны.
Очевидно, что я не могу получить этот fd из набора, потому что я все еще хочу получать уведомления о новых данных на нем.
Я НЕ хочу закрывать его, потому что это не труба с однократным использованием, мне нравится повторять одно и то же и не выбрасывать их... помимо прочего, у меня больше нет названия канала, у меня есть только дескриптор файла (и получение имени файла от fd кажется стервой... Я тоже гуглил это...)
Я все еще верю в мощь Linux и в том, что для этого должен быть лучший (более производительный / безопасный режим).
Вот что я прочитал, но не помог решить проблему.
- http://www.greenend.org.uk/rjk/tech/poll.html - Опрос, похоже, доставляет массу удовольствия...
- сокет: постоянно получая POLLHUP при половинном закрытии - нет, я не хочу закрывать его, это не сокет, это труба (которая в любом случае должна открываться первой на стороне считывателя)
- Как использовать функцию poll C для просмотра именованных каналов в Linux? - Это моя проблема, но как ее решить? Когда я открываю трубу, она наполовину закрыта (фактически наполовину открыта:), как после того, как кто-то что-то написал в ней и закрыл свой конец после них, но я получаю шторм POLLHUP только на полузакрытых, а не наполовину открытых (так что есть разница).
В отчаянии я пытался делать даже такие вещи (что не помогло):
int newfd = dup(fds[i].fd);
close(fds[i].fd);
dup2(newfd, fds[i].fd);
close(newfd);
Есть идеи? Я делаю что-то совершенно не так?
(Я всегда могу вернуться к тому, чтобы просто периодически читать все каналы (что на самом деле работает), сейчас это не критично к задержке, но я не знаю, что бы я делал, если бы это было...)
Вот некоторый код для воспроизведения моей проблемы (это не рабочий код, который я пытаюсь создать, очевидно, существует более 1 канала, который я хочу опрашивать...)
#include <stdio.h>
#include <sys/types.h> // mkfifo
#include <sys/stat.h> // mkfifo
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <poll.h>
int main(int argc, char **argv) {
char* pipename = "/tmp/fifo";
mkfifo(pipename, S_IWUSR | S_IRUSR | S_IRGRP);
int fd = open(pipename, O_RDONLY | O_NONBLOCK); /// O_ASYNC, O_SYNC
struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = POLLIN;
fds[0].revents = 0;
while (1) {
int res = poll(fds, 1, 1000);
if (res<0) { perror("poll"); return 1; }
if (res==0) { printf(".\n"); continue; }
printf("Poll [%d]: 0x%04x on %d\n", 0, fds[0].revents, fds[0].fd);
char buff[512];
int count = (int)read(fds[0].fd, buff, (size_t)(sizeof(buff)-1));
if (count>=0) {
buff[count] = 0;
printf("Pipe read %d bytes: '%s'\n", count, buff);
usleep(1000*100); /// cpu protector sleep for POLLHUP :)
}
}
return 0;
}
Заметки:
Я использую gcc (4.6.3) на платформе Linux (lubuntu) (x64). Но в конце я хочу сделать кросс-компиляцию для встроенной цели.
Я уверен, что я, должно быть, пропустил некоторую информацию, так что спросите...
Решение / Обход:
- Обходной путь #1, предложенный mark4o, заключается в открытии канала с
O_RDWR
вместоO_RDONLY
, Таким образом, вы не получите постоянныйPOLLHUP
-s (конечно, вы не получите ведьму может быть проблемой). Также читателю понадобится разрешение на запись в канал (которое в некоторых случаях может отсутствовать).
1 ответ
Поскольку каналы предоставляют только один однонаправленный канал (а не отдельный двунаправленный канал для каждого клиента, такого как сокет), они обычно используются, когда у вас есть только один процесс, который должен отправлять данные только одному другому процессу. Когда писатель закрывает трубу, POLLHUP
(зависание) сообщает читателю, что канал закрыт, и он может завершить обработку и завершиться.
Можно использовать канал с несколькими авторами, но вам нужно быть осторожным, если сообщения могут быть больше, чем PIPE_BUF
или 512 байт. В противном случае, поскольку это только один канал, сообщения от нескольких авторов, пишущих одновременно, могут чередоваться. Кроме того, поскольку это один канал, вы не сможете определить, является ли длинное сообщение одной записью одного клиента или несколькими записями нескольких клиентов, если у вас нет соглашения, например, одна строка (завершается новой строкой) на каждое сообщение клиента,
POLLHUP
указывает на то, что последний писатель закрыл канал и сохраняется до тех пор, пока другой процесс не откроет канал для записи или пока он не будет закрыт всеми читателями. Если вы не хотите этого, откройте трубу с O_RDWR
вместо O_RDONLY
так что труба останется открытой. Это работает, потому что тогда всегда будет писатель (ваша программа), пока он у вас открыт.