Как сделать, чтобы соединение не удалось, когда сервер не готов? - PullRequest
1 голос
/ 26 июня 2011

Я пишу библиотеку для локального IPC, которая должна действовать как сервер и клиент. Стратегия состоит в том, чтобы потерпеть неудачу и попытаться снова, если сервер не готов.

Для этого теста я создал два процесса, которые взаимодействуют как сервер, так и клиент.

Но у меня есть проблема с моей текущей реализацией, потому что код клиента не перестает работать, когда сервер занят.

Проблема лучше всего иллюстрируется фрагментом из strace:

execve("./RemoteSubjects", ["./RemoteSubjects"], [/* 72 vars */]) = 0

// Client A starts
28069       .000105 socket(PF_FILE, SOCK_STREAM, 0) = 3
28069       .000031 fcntl(3, F_GETFL)   = 0x2 (flags O_RDWR)
28069       .000006 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
28069       .000047 unlink("/tmp/A.ipc") = 0
28069       .000007 bind(3, {sa_family=AF_FILE, path="/tmp/A.ipc"}, 110) = 0
28069       .000007 listen(3, 0 ) = 0

// Client B starts
28070       .000031 socket(PF_FILE, SOCK_STREAM, 0) = 3
28070       .000012 fcntl(3, F_GETFL)   = 0x2 (flags O_RDWR)
28070       .000005 fcntl(3, F_SETFL, O_RDWR|O_NONBLOCK) = 0
28070       .000030 unlink("/tmp/B.ipc") = 0
28070       .000034 bind(3, {sa_family=AF_FILE, path="/tmp/B.ipc"}, 110) = 0
28070       .000027 listen(3, 0)        = 0

// Client A creates a socket, which it intend to use for communication with B
28069       .000023 socket(PF_FILE, SOCK_STREAM, 0) = 4
28069       .000016 fcntl(4, F_GETFL)   = 0x2 (flags O_RDWR)
28069       .000024 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0

// Client B creates a socket, which it intend to use for communication with A
28070       .000038 socket(PF_FILE, SOCK_STREAM, 0) = 4
28070       .000016 fcntl(4, F_GETFL <unfinished ...>

// Client A connects to B
28069       .000004 connect(4, {sa_family=AF_FILE, path="/tmp/B.ipc"}, 110 <unfinished ...>

// Client B creates a socket, which it intend to use for communication with A
28070       .000011 <... fcntl resumed> ) = 0x2 (flags O_RDWR)
28070       .000007 fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK) = 0

// Client B connects to A
28070       .000015 connect(4, {sa_family=AF_FILE, path="/tmp/A.ipc"}, 110 <unfinished ...>

// Client A's connect returned
28069       .000010 <... connect resumed> ) = 0

// Here is what I do not understand... Why does connect returns 0 when the backlog
// is set to 0 and B has not accepted?

Я хотел бы, чтобы произошел сбой соединения, пока я не поймаю сервер в его цикле событий, ожидая опроса, чтобы сообщить об активности в файловом дескрипторе 3. Мне следует правильно установить тайм-аут (я думаю, SO_RCVTIMEO / SO_SNDTIMEO), разрешающий соединение заблокировать на 10 мс, чтобы увеличить изменения для сервера, чтобы принять соединение.

Но как мне это исправить и убедиться, что соединение не удалось, если accept не вызывается?

1 Ответ

2 голосов
/ 27 июня 2011

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

Что касается аргумента backlog , POSIX утверждает, что это подсказка :

Аргумент backlog предоставляет подсказку реализации, которую реализация должна использовать для ограничения числа ожидающих соединений в очереди прослушивания сокета.

Там также сказано:

Аргумент backlog 0 может позволить сокету принимать соединения, и в этом случае длина очереди прослушивания может быть установлена ​​равной минимальному значению, определяемому реализацией.

Если вы хотите, чтобы connect() не удался, не звоните listen(), пока не будете готовы к успеху. И после вызова accept() закройте сокет прослушивания, если вы не хотите, чтобы больше было успешных соединений (любые дополнительные соединения, находящиеся в очереди приема, будут прерваны). В качестве альтернативы, приложение должно отправлять некоторые данные через сокет, как только оно принимает соединение (если оно этого еще не делает); если другая сторона ничего не получает в течение определенного периода времени, она может закрыть соединение.

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