«Сброс соединения по одноранговой сети», если сервер вызывает close () сразу после write () - PullRequest
2 голосов
/ 04 июня 2011

У меня есть сервер AF_INET / SOCK_STREAM, написанный на C, работающий на Android / Linux, который выглядит примерно так:

...
for (;;) {
    client = accept(...);
    read(client, &message, sizeof(message));
    response = process(&message);
    write(client, response, sizeof(*response));
    close(client);
}

Насколько я знаю, вызов close не должен прерывать соединение с клиентом немедленно, но, очевидно, так и происходит: клиент сообщает "Сброс соединения по одноранговому узлу", прежде чем он сможет прочитать ответ сервера.

Если я вставлю задержку между write() и close(), клиент сможет прочитать ответ, как ожидалось.

Я получил подсказку, что это может быть связано с параметром SO_LINGER, но я проверил его значение, и оба члена struct linger (l_onoff, l_linger) имеют значение ноль.

Есть идеи?

Ответы [ 3 ]

3 голосов
/ 05 июня 2011

Стивенс описывает конфигурацию, в которой это может произойти, но это зависит от того, отправляет ли клиент больше данных после того, как сервер вызвал close () (после того, как клиент должен «знать», что соединение закрывается). UNP 2nd ed s5.12.

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

1 голос
/ 08 июня 2014

Соединение сбрасывается при вызове close() при соединении с отправляемыми данными. Специально для этого случая используется последовательность shutdown() с флагом SHUT_WR и последующей блокировкой read().

Выключение записывающего конца сокета отправляет FIN и немедленно возвращается, а указанный read () блокируется и возвращает 0, как только ваш коллега ответит с FIN в установленном порядке. По сути, это то, что вам нужно вместо задержки между write() и close(), о которой вы говорите.

В этом случае вам не нужно ничего делать с опциями linger, оставьте все по умолчанию.

0 голосов
/ 05 июня 2011

SO_LINGER должен быть установлен (т. Е. Установлен на 1, а не на 0), если вы хотите, чтобы данные в очереди отправлялись до того, как будет выполнено закрытие.

SO_LINGER Задерживается при закрытии (), если данные присутствуют. Эта опция контролирует действие, предпринимаемое при отправке сообщений очередь на сокете и close () есть выполнила. Если SO_LINGER установлен, то система должна блокировать вызывающий поток во время закрытия (), пока он не может передать данные или до истечения времени. Если SO_LINGER не указан, и выдается close (), система обрабатывает вызов таким образом, что позволяет вызывающий поток, чтобы продолжить как можно быстрее насколько это возможно. Эта опция занимает структура, как это определено в заголовок, чтобы указать состояние опциона и задержка интервал.

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