#c #linux #sockets #network-programming
Вопрос:
У меня есть сервер, на котором написано, C
что соединение закрывается, если соединение простаивает в течение определенного времени. У меня есть проблема (которая редко случается). Чтение не удается на стороне клиента, и в нем говорится Connection broken
. Я подозреваю, что сервер закрывает соединение, и клиент одновременно отправляет некоторые данные.
Рассмотрим следующий сценарий (A-сервер, B-клиент).
B
инициирует соединение, и соединение междуA
B
ними устанавливается.B
находится в режиме ожидания, и время ожидания ожидания достигнуто.A
инициирует закрытие- Прежде
B
чем получитьFIN
отA
, он начинает отправлять запрос наA
- После
B
отправки запроса он прочитает ответ
Так A
как уже закрыл соединение, B
не может читать.
Мои вопросы таковы
- Возможна ли такая ситуация ?
- Как обрабатывать время простоя для клиентов?
- Как правильно закрыть соединение между
A
иB
(избегайтеB
отправки запроса во время процесса). Короче говоря, как закрыть соединение атомарно?
Комментарии:
1. Вы не должны использовать форматирование кода для выделения, форматирование кода используется для кода. Вместо этого используйте жирный шрифт или курсив, как вы делали бы при написании письма в MS Word.
2. 1. Да. 2. Если время ожидания составляет 5 секунд, клиент никогда не должен допускать более одной секунды между сообщениями. Если клиенту нечего отправлять, и прошла одна секунда, он должен просто отправить сообщение «Сохранить жизнь», т. е. сообщение без содержимого. Отрегулируйте значение тайм-аута по желанию, но тайм-аут должен быть щедрым по сравнению со скоростью поддержания жизни. 3. Перед закрытием соединения (из-за тайм-аута) сервер должен отправить клиенту сообщение «обнаружен тайм-аут».
3. Я не могу согласиться со всеми предложениями о том, чтобы сервер отправлял сообщение о таймауте. На этом этапе сервер должен предположить, что соединение разорвано, и оно может быть разорвано, и в любом случае сообщение о тайм-ау может никогда не поступить в клиент, или клиент может неправильно ответить на него: и если сервер затем закроет соединение, клиент все равно может получить
broken pipe
. Вам просто нужно смириться с этимbroken pipe
сообщением. Все, что делают сообщение о таймауте и ответ, — это добавляют дополнительные возможности дляbroken pipe
возникновения.
Ответ №1:
Благодаря моему немногим более чем рудиментарному сетевому опыту… и предполагая, что вы говорите о соединении, ориентированном на соединение, таком как TCP/IP, в отличие от UDP/IP, которое не имеет подключения.
- Да, конечно. Вы не можете избежать этого.
- Существует несколько способов сделать это, но все они включают в себя: Отправить что-то от клиента до истечения времени ожидания сервера. Если у клиента нет данных для отправки, пусть он отправит что-то вроде «знака жизни». Это может быть пустое сообщение данных, все зависит от протокола вашего приложения. Или сделайте тайм-аут таким долгим, как это необходимо, включая некоторую маржу. Некоторое время ожидания протокола только после 3-кратного допустимого простоя.
- Вы не можете закрыть соединение атомарно, так как клиент и сервер разделены. Каждому пакету в сети требуется некоторое время для передачи, и оба могут начать отправку в один и тот же момент, сервер-свое заключительное сообщение, а клиент — новое сообщение данных. Вы ничего не можете с этим поделать.
Вам нужно заставить клиента правильно справиться с этой ситуацией. Например, он может принять такое разорванное соединение и интерпретировать его как закрытое. У вас уже должна быть какая-то реакция, если сервер закрывает соединение, пока клиент простаивает.
Ответ №2:
Как правильно закрыть соединение между A и B (избегайте отправки запроса B во время процесса).
- Сервер обнаруживает тайм-аут
- Сервер отправляет Клиенту сообщение об обнаружении тайм-аута
- Сервер ждет ответа (если время ожидания истекло, предположим, что клиент мертв)
- если клиент получает обнаружение тайм-аута от сервера, он отвечает ACK (или что-то в этом роде)
- если Сервер получает подтверждение от Клиента, то «изящно» закрывает соединение
- отныне ни Сервер, ни Клиент не должны отправлять/получать какие — либо сообщения (после отправки ACK не закрывайте соединение сразу со стороны клиента, не задерживайтесь на согласованный тайм-аут-см. setsockopt: SO_LINGER)
Кроме того, как и в других предложенных ответах, клиент должен отправлять сердцебиение в режиме ожидания (чтобы избежать обнаружения тайм-аута).
Комментарии:
1. Это также прекрасное решение, но оно не распространяется на ситуацию, когда соединение прерывается по другим причинам. Клиенту все еще необходимо обработать ошибку отправки.
2. @thebusybee Я не думаю, что здесь проблема в этом. Конечно, вы правы в том, что ошибка передачи должна быть правильно обработана, но, насколько я понял операцию, проблема возникает не тогда, когда возникает ошибка, а при нормальных обстоятельствах, что, кстати говоря. может и случится. Я думал, что правильное рукопожатие будет решением.
3. Все это просто повторяет то, что уже делает TCP/IP. И что произойдет, если сервер истечет время ожидания, считывая ответ на тайм-аут от клиента? В этом нет никакого преимущества.
4. @user207421 Со страницы руководства
send
: В send () не подразумевается никаких указаний на невозможность доставки. Локально обнаруженные ошибки обозначаются возвращаемым значением -1. Как это помогает решить вопрос об операции? Операция ищет эту гарантию.5. У ОП не может быть такой гарантии именно по той причине, о которой вы заявили. Ваше сообщение о тайм-ау не гарантировано будет доставлено больше, чем что-либо другое, и сервер не может сказать, было ли оно доставлено или нет.