Что происходит, когда сервер закрывает соединение, а клиент одновременно отправляет некоторые данные?

#c #linux #sockets #network-programming

Вопрос:

У меня есть сервер, на котором написано, C что соединение закрывается, если соединение простаивает в течение определенного времени. У меня есть проблема (которая редко случается). Чтение не удается на стороне клиента, и в нем говорится Connection broken . Я подозреваю, что сервер закрывает соединение, и клиент одновременно отправляет некоторые данные.

Рассмотрим следующий сценарий (A-сервер, B-клиент).

  1. B инициирует соединение, и соединение между A B ними устанавливается.
  2. B находится в режиме ожидания, и время ожидания ожидания достигнуто.
  3. A инициирует закрытие
  4. Прежде B чем получить FIN от A , он начинает отправлять запрос на A
  5. После B отправки запроса он прочитает ответ

Так A как уже закрыл соединение, B не может читать.

Мои вопросы таковы

  1. Возможна ли такая ситуация ?
  2. Как обрабатывать время простоя для клиентов?
  3. Как правильно закрыть соединение между A и B (избегайте B отправки запроса во время процесса). Короче говоря, как закрыть соединение атомарно?

Комментарии:

1. Вы не должны использовать форматирование кода для выделения, форматирование кода используется для кода. Вместо этого используйте жирный шрифт или курсив, как вы делали бы при написании письма в MS Word.

2. 1. Да. 2. Если время ожидания составляет 5 секунд, клиент никогда не должен допускать более одной секунды между сообщениями. Если клиенту нечего отправлять, и прошла одна секунда, он должен просто отправить сообщение «Сохранить жизнь», т. е. сообщение без содержимого. Отрегулируйте значение тайм-аута по желанию, но тайм-аут должен быть щедрым по сравнению со скоростью поддержания жизни. 3. Перед закрытием соединения (из-за тайм-аута) сервер должен отправить клиенту сообщение «обнаружен тайм-аут».

3. Я не могу согласиться со всеми предложениями о том, чтобы сервер отправлял сообщение о таймауте. На этом этапе сервер должен предположить, что соединение разорвано, и оно может быть разорвано, и в любом случае сообщение о тайм-ау может никогда не поступить в клиент, или клиент может неправильно ответить на него: и если сервер затем закроет соединение, клиент все равно может получить broken pipe . Вам просто нужно смириться с этим broken pipe сообщением. Все, что делают сообщение о таймауте и ответ, — это добавляют дополнительные возможности для broken pipe возникновения.

Ответ №1:

Благодаря моему немногим более чем рудиментарному сетевому опыту… и предполагая, что вы говорите о соединении, ориентированном на соединение, таком как TCP/IP, в отличие от UDP/IP, которое не имеет подключения.

  1. Да, конечно. Вы не можете избежать этого.
  2. Существует несколько способов сделать это, но все они включают в себя: Отправить что-то от клиента до истечения времени ожидания сервера. Если у клиента нет данных для отправки, пусть он отправит что-то вроде «знака жизни». Это может быть пустое сообщение данных, все зависит от протокола вашего приложения. Или сделайте тайм-аут таким долгим, как это необходимо, включая некоторую маржу. Некоторое время ожидания протокола только после 3-кратного допустимого простоя.
  3. Вы не можете закрыть соединение атомарно, так как клиент и сервер разделены. Каждому пакету в сети требуется некоторое время для передачи, и оба могут начать отправку в один и тот же момент, сервер-свое заключительное сообщение, а клиент — новое сообщение данных. Вы ничего не можете с этим поделать.

    Вам нужно заставить клиента правильно справиться с этой ситуацией. Например, он может принять такое разорванное соединение и интерпретировать его как закрытое. У вас уже должна быть какая-то реакция, если сервер закрывает соединение, пока клиент простаивает.

Ответ №2:

Как правильно закрыть соединение между A и B (избегайте отправки запроса B во время процесса).

  • Сервер обнаруживает тайм-аут
  • Сервер отправляет Клиенту сообщение об обнаружении тайм-аута
  • Сервер ждет ответа (если время ожидания истекло, предположим, что клиент мертв)
  • если клиент получает обнаружение тайм-аута от сервера, он отвечает ACK (или что-то в этом роде)
  • если Сервер получает подтверждение от Клиента, то «изящно» закрывает соединение
  • отныне ни Сервер, ни Клиент не должны отправлять/получать какие — либо сообщения (после отправки ACK не закрывайте соединение сразу со стороны клиента, не задерживайтесь на согласованный тайм-аут-см. setsockopt: SO_LINGER)

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

Комментарии:

1. Это также прекрасное решение, но оно не распространяется на ситуацию, когда соединение прерывается по другим причинам. Клиенту все еще необходимо обработать ошибку отправки.

2. @thebusybee Я не думаю, что здесь проблема в этом. Конечно, вы правы в том, что ошибка передачи должна быть правильно обработана, но, насколько я понял операцию, проблема возникает не тогда, когда возникает ошибка, а при нормальных обстоятельствах, что, кстати говоря. может и случится. Я думал, что правильное рукопожатие будет решением.

3. Все это просто повторяет то, что уже делает TCP/IP. И что произойдет, если сервер истечет время ожидания, считывая ответ на тайм-аут от клиента? В этом нет никакого преимущества.

4. @user207421 Со страницы руководства send : В send () не подразумевается никаких указаний на невозможность доставки. Локально обнаруженные ошибки обозначаются возвращаемым значением -1. Как это помогает решить вопрос об операции? Операция ищет эту гарантию.

5. У ОП не может быть такой гарантии именно по той причине, о которой вы заявили. Ваше сообщение о тайм-ау не гарантировано будет доставлено больше, чем что-либо другое, и сервер не может сказать, было ли оно доставлено или нет.