Невозможно синхронизировать блокировку чтения и записи в FIFO - PullRequest
0 голосов
/ 21 мая 2011

Я делаю очень простую программу, которая состоит из небольшого API, используемого клиентами и серверным процессом.Клиентские процессы и серверные процессы обмениваются данными парой FIFO (один с запросами к серверу, а другой с ответами с сервера).

  • сервер продолжает читать запросы FIFO с блокирующим чтением (флаг O_RDWR)
  • клиенты пишут запрос на запросы FIFO (флаг O_WRONLY)
  • сервер читает запрос, он работает над ним и записывает ответ в ответ FIFO (флаг O_WRONLY)
  • клиенты читают ответ (флаг O_RDONLY): если сервер не должен передавать какие-либо данные (яозначает неопределенный длинный буфер), тогда ответа, записанного в FIFO, будет достаточно, и задание будет выполнено
  • else ...
  • , который клиент читает в ответе, который сервер собирается отправитьданные, поэтому он открывает ответы FIFO снова (флаг O_RDONLY)
  • сервер записывает данные с (флаг O_WRONLY)

Кажется, что последняя запись не блокирует процесс сервера, покаклиент читает с другой стороны: почему?что мне не хватает?Чтобы достичь своей цели, я должен был поставить sleep (1) перед вызовом write, но это работает только с какими-то запросами к серверу: как я могу помочь вам помочь мне?

КОД СЕРВЕРА

                /* until here everything is ok: client read the response and waits for the buffer */
                sleep(1);
                /* open the FIFO and send the buffer */
                if((fifofrom = open(FIFOFROMMMBOXD, O_WRONLY)) == -1)   logMmboxd("error in opening FIFOFROM again for the buffer\n", 1);
                else                                                    logMmboxd("opened FIFOFROM again for the buffer\n", 0);

                if((write(fifofrom, mails, sizeof(mmbox_mail_complete)*m)) != sizeof(mmbox_mail_complete)*m)   logMmboxd("error in writing FIFOFROM again for the buffer\n", 1);
                else                                                                                           logMmboxd("written on FIFOFROM again for the buffer\n", 0);      
                close(fifofrom); 

                logMmboxd("messages list definitely sent\n", 0);

КОД КЛИЕНТА

void lockUp(Request *request, Response *response, void **buffer)
{
int fifofrom, fifoto, lock;     

/* lockto access the FIFOs */
if((lock = open(LOCK, O_RDONLY)) == -1)   logMmboxman("error in opening LOCK\n", 1);
else                                      logMmboxman("opened LOCK\n", 0);

if(flock(lock, LOCK_EX) == -1)            logMmboxman("error in acquiring LOCK\n", 1);              
else                                      logMmboxman("acquired LOCK\n", 0);  

/* open the FIFO and write the request */
if((fifoto = open(FIFOTOMMBOXD, O_WRONLY)) == -1)   logMmboxman("error in opening FIFOTO\n", 1); 
else                                                logMmboxman("opened FIFOTO\n", 0);  

if((write(fifoto, request, sizeof(Request))) != sizeof(Request))   logMmboxman("error in writing FIFOTO\n", 1);
else                                                               logMmboxman("written on FIFOTO\n", 0);
close(fifoto);

/* waiting for response on FIFOFROM */
if((fifofrom = open(FIFOFROMMMBOXD, O_RDONLY)) == -1)   logMmboxman("error in opening FIFOFROM\n", 1);
else                                                    logMmboxman("opened FIFOFROM\n", 0);

if((read(fifofrom, response, sizeof(Response))) != sizeof(Response))   logMmboxman("error in reading FIFOFROM\n", 1);
else                                                                   logMmboxman("read from FIFOFROM\n", 0);
close(fifofrom);

/* if size>0 then the server has to send a buffer of data to me! */
if(response->size)
{
    if((fifofrom = open(FIFOFROMMMBOXD, O_RDONLY)) == -1)   logMmboxman("error in opening FIFOFROM again for the buffer\n", 1);
    else                                                    logMmboxman("opened FIFOFROM again for the buffer\n", 0);

    *buffer = (void*)malloc(response->size);

    if(read(fifofrom, *buffer, response->size) != response->size)   logMmboxman("error in reading FIFOFROM again for the buffer\n", 1);
    else                                                            logMmboxman("read from FIFOFROM again for the buffer\n", 0);
    close(fifofrom);    
}

/* read the response: I release the lock */
if(flock(lock, LOCK_UN) == -1)            logMmboxman("error in releasing LOCK\n", 1);              
else                                      logMmboxman("released LOCK\n", 0);  

return;
}

1 Ответ

0 голосов
/ 21 мая 2011

Итак (1) ваши рассуждения о синхронизации FIFO верны;(2) есть вероятность того, что linux испортится;Итак (3) у вас есть ошибка.

Трудно сказать, но, поскольку вы изначально открываете сервер fifo как O_RDWR, возможно, вы не закрываете то, что думаете?Возможно, у вас работает второй клиент, у которого уже есть этот fifo, открытый как считыватель, и когда вы снова открываете его как O_WRONLY, он не блокируется?

В любом случае вашей реальной проблемой является разработанный вами протокол.Я не вижу необходимости в замках или в том, чтобы держать их открытыми и закрывать ящики.Вам действительно нужен разумный протокол связи.

Обычно это что-то вроде:

(1) на сервере есть хорошо известная fifo, которую клиенты открывают и пишут в нее.

(2) клиенты передают код транзакции или что-то, указывающее, что это начальный запрос.Включен некоторый метод установления сервером обратного соединения с клиентом.Это может быть полное имя пути или просто pid, который и клиент, и сервер используют с предопределенным путем для создания второго fifo (например, оба открывают "/ tmp / myfifo_pid" или что-то подобное).

(3) После того, как клиент и сервер откроют второй fifo, все дальнейшие клиентские запросы к серверу включают pid (или любой другой), чтобы сервер знал, куда выводить запрос.

(4) После того, как все сделано,клиент отправляет транзакцию с указанием так, что сервер может закрыть 2-е число.Клиент делает то же самое.

(5) Повторите для всех клиентов.

Обратите внимание, что вам необходимо указать формат для ваших сообщений.Проверенными временем методами являются использование длинного кода (кажется, что вы пытаетесь) или какой-либо разделитель конца сообщения (например, новая строка).

Редактировать

Возможный формат сообщения:

length | trancode || data |

где length указывает, сколько последующих байтов составляют все сообщение, транскод указывает и операцию (например, открыть мой вывод fifo, закрытьотправьте данные, что угодно), а данные - это то, что подходит для транзакции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...