Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > Сокеты. Не понятны детали работы.


Автор: wowka19 22.4.2016, 07:18
1. Как серверу узнать, что сокет на клиенте закрылся?
2. Как клиенту узнать, что соответсвующий ему сокет на сервере закрылся?

3. Главный вопрос:

Код

//ПСЕВДОКОД СЕРВЕРА:
client_socket_1 = server_socket.accept()  // дождался клиента
foo(client_socket_1)  // что-то с ним сделал

/*
В это время клиент закрыл сокет (что-то там произошло неладное и сервер не узнал об этом)
и попробовал подключиться к серверу снова.
Что тогда произойдет в следующей строке?
*/
client_socket_2 = server_socket.accept()
/*
Придет ли в client_socket_2 тот же самый клиент?
И что тогда будет с client_socket_1?
Если и в client_socket_1 и в client_socket_2 будут доступы к одному и тому же клиенту, то что произойдет при client_socket_1.close()? а при client_socket_2.close()?
*/


Автор: feodorv 22.4.2016, 08:33
Если сеть в порядке, а сокет на противоположной стороне закрыт штатными средствами, то наша сторона при операциях с сокетом тем или иным способом сообщает пользователю, что сокет на противоположной стороне закрыт. При записи - это ошибка, при чтении же нам возвращается не ошибка, а значение 0 в качестве числа прочтенных байтов из сокета. Иначе при операциях с сокетом на нашей стороне возвращается ошибка. Обычно это ECONNRESET. 

Если что-то произошло по пути следования посланного пакета от нас к удаленному узлу такое, что промежуточные маршрутизаторы посылают нам в ответ сообщения ICMP, то в ответ на чтение/запись в/из сокета можно получить EHOSTUNREACH или ECONNABORTED (возможно, ещё что-то, увы я всё подзабыл) . Если маршрутизаторы не сообщают нам о проблемах в сети (например, ICMP под запретом), то тогда наша сторона остаётся не в курсе текущих событий. Тогда могут сработать различные таймауты, если включен keepalive. Тогда по достижению таймаута приходит ошибка ENETRESET или ETIMEDOUT. Иначе соединение TCP держится, даже если оно уже по факту не живое. Некоторые вопросы объяснены http://www.hardline.ru/4/49/1236/1630-16.html.

Такое поведение не зависит от того, сервер ты ил клиент.


Цитата(wowka19 @  22.4.2016,  07:18 Найти цитируемый пост)
//ПСЕВДОКОД СЕРВЕРА:
client_socket_1 = server_socket.accept()  // дождался клиента
foo(client_socket_1)  // что-то с ним сделал
/*
В это время клиент закрыл сокет (что-то там произошло неладное и сервер не узнал об этом)
и попробовал подключиться к серверу снова.
Что тогда произойдет в следующей строке?
*/
client_socket_2 = server_socket.accept()

Если у сервера есть свободные слоты соединения, то тогда клиент вторично подключится с серверу. С точки зрения сервера, это будет подключение ещё одного клиента, а не того же самого. client_socket_1 будет жить свой жизнью, отдельной от client_socket_2.

Автор: wowka19 23.4.2016, 17:03
Цитата(feodorv @  22.4.2016,  08:33 Найти цитируемый пост)
Если у сервера есть свободные слоты соединения, то тогда клиент вторично подключится с серверу. С точки зрения сервера, это будет подключение ещё одного клиента, а не того же самого. client_socket_1 будет жить свой жизнью, отдельной от client_socket_2.

Но когда клиент установит повторное соединение он выделит под него порт, а так как порт в предыдущем соединении освободился, то он же может быть выдан под повторное соединение. Выходит, что сервер примет новое для него соединение (первое он еще держит) с точно такими же IP и портом. Как это разруливает стандарт? Что произойдет? Ведь в этом случае и client_socket_1 и client_socket_2 будут иметь тот же адрес, а так как протокол TCP кроме как порта не предоставляет больше никаких уникальных для соединений атрибутов, то как сервер будет разделять client_socket_1.send() и client_socket_2.send()? И что будет с client_socket_1, он "оживет"? А в случае client_socket_1.close() как скажется на client_socket_2?

Автор: feodorv 24.4.2016, 09:16
Если сервер при наличии установленного соединения для той же удаленной пары IP/порт получит пакет SYN, то этот пакет будет отброшен, соединение №2 не будет установлено. 

Автор: wowka19 24.4.2016, 11:57
Цитата(feodorv @  24.4.2016,  09:16 Найти цитируемый пост)
Если сервер при наличии установленного соединения для той же удаленной пары IP/порт получит пакет SYN, то этот пакет будет отброшен, соединение №2 не будет установлено.

Тогда клиент будет безрезультатно биться к серверу, пока тот не закроет первый клиентский сокет как-то так: client_socket_1.close() ?

Автор: feodorv 24.4.2016, 20:22
Цитата(wowka19 @  24.4.2016,  11:57 Найти цитируемый пост)
Тогда клиент будет безрезультатно биться к серверу, пока тот не закроет первый клиентский сокет как-то так: client_socket_1.close() ? 

Реакция севера, когда к нему постучится клиент с того же IP и того же порта, что и прошлое зависшее соединение, зависит от реализации стека TCP/IP на сервере. Сервер может и отослать пакет обратно клиенту, что соединение невозможно. Тогда клиент не будет ждать определенных таймаутов, пока поймет, что соединения не будет. Да, именно в там случае соединение не устанавливается. Ситуация, конечно, возможная, но маловероятная. Более того, следующая попытка установления соединения клиентом с сервером закончится успехом, так как клиентская ОС для клиента выберет уже другой порт. Так что не всё так печально)))

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)