Я пишу клиент-серверное приложение, используя posix FIFO для связи. И клиент, и сервер представляют собой однопоточное и однопроцессное приложение.
Сервер предназначен для работы с несколькими клиентами. У каждого клиента есть своя пара именованных каналов: один для отправки сообщений от Сервера этому Клиенту, а другой - для отправки сообщений от Клиента на Сервер.
Идея довольно проста: сервер просматривает все каналы от клиента к серверу и проверяет, есть ли там что-нибудь для чтения.
Моя первая реализация была примерно такой:
/* SERVER */
int desc = open(pipeName, O_RDONLY | O_NDELAY); //1
assert(desc > 0); //just simplyfing error handling
int read = read(desc, buffer, BUFSIZE); //2
if(read > 0)
do_stuff();
close(desc); //3
/* CLIENT */
int desc = open(pipeName, O_WRONLY) //4
assert(desc > 0); //just simplyfing error handling
int read = write(desc, buffer, BUFSIZE) //5
close(desc); //6
Насколько мне известно, этот код недействителен.
Есть условия гонки и, например, такой порядок вызовов, как: 1, 2, 4, 3, 5, 6 - вероятно, вызовет SIGPIPE.
Проблема в том, что открытие неблокирующего чтения всегда успешно, даже если на другой стороне PIPE нет писателя. Это означает, что если клиент заблокируется на open (), тогда сервер сделает неблокирующее открытие (что разблокирует клиента), а затем read (), который вернет 0, потому что в данный момент ничего не будет в PIPE и close () после этого, тогда, когда управление будет вернитесь к клиенту, который хочет выполнить write () на открытом PIPE, это вызовет SIGPIPE, поскольку считыватель больше не доступен (сервер уже закрыл канал).
На данный момент я вижу два решения:
- Обработайте SIGPIPE в клиенте с помощью "tryAgain ()" - это выглядит очень плохо, если я сделаю это, нет никакой гарантии, что он будет работать в любой момент - это будет зависеть от возможности хорошего порядка обработки команд ...
- Продолжайте читать PIPE open все время на сервере (откройте его один раз и закройте, когда соединение будет считаться завершенным) - это неудобно для моей архитектуры приложения, но, конечно, возможно. Думаю, это решит проблему, но я не уверен в этом.
Вот мои вопросы:
- Правильный ли какой-либо из этих двух подходов?
- Есть ли другой способ справиться с этим сценарием?
- Как вы думаете, второе решение будет работать правильно?
- Что бы вы выбрали и почему?
Спасибо за каждый ответ.
assert(desc != -1);
илиassert(desc >= 0);
, посколькуopen()
возвращает-1
в случае ошибки или неотрицательное целое число в случае успеха. - person alk   schedule 26.05.2013