2016-08-29 2 views
0

Как сетевой инженер, я очень хорошо знаком с операциями TCP. Будучи программистом, я занимался программированием сокетов, но никогда не писал никаких производственных услуг.TCP-открытые соединения TCP, Winsock, Listen/Accept Behavior

У нас есть система поставщиков, которая интегрируется с камерами PTZ (панорамирование/наклон/масштабирование). Камеры наблюдают за пациентами. Данные камеры передаются на сервер поставщика. Сервер поставщика передает данные камеры клиентам. (Это делает больше, но это простой случай.) Если клиент хочет настроить камеру, клиент отправляет пользовательскую команду в настраиваемую службу на сервере поставщика. Сервер интерпретирует команду и отправляет ее на камеру. Камера движется.

У нас возникла проблема, когда служба PTZ на сервере сбой. Во время тестирования с захватами сети мы обнаружили, что служба разбилась примерно в то время, когда nmap выполнил полуоткрытое (эмбриональное) соединение - nmap отправил SYN, сервер ответил с SYN/ACK, nmap не отправил окончательный ACK. Сервер отправил дубликаты SYN/ACK, пытаясь завершить сеанс и не удалось.

Что я хочу понять: служба использует listen для просмотра TCP-соединений, а затем использует accept, чтобы принять соединение. В какой момент listen рассказать об услуге есть новое соединение, готовое быть accept ed? Должно ли быть установлено соединение TCP до того, как listen передает его службе, чтобы она была accept? Или сервер просто должен вернуть SYN/ACK до того, как listen сообщит службе?

Если рукопожатие должно быть полным - SYN, SYN/ACK, ACK - перед сообщением listen, то я могу пойти по неправильному пути. Если сокет просто нуждается в доступе к SYN/ACK, может возникнуть проблема с обработкой службы неполного сеанса. Другое тестирование, когда мы завершаем сеанс TCP и отправляем фиктивные данные, пытающиеся вызвать службу, - не привело к сбою службы. Но повторный тест nmap довольно надежно сбивает его, поэтому я склоняюсь к проблеме полуоткрытого соединения.

ответ

0

listen() сам создает резервную очередь, открывает связанный порт для связи, а затем выходит. За кулисами стек сокетов теперь пассивно прослушивает соединения на уровне ОС, кэширует ожидающие подключения в очереди на отставание и завершает их рукопожатие. Доступны только полностью установленные соединения для accept(), WSAAccept() и AcceptEx().

После listen() выходов, в зависимости от режима, в котором код приложения используется для сокета ввода/вывода (блокировка, без блокировки, перекрывающегося ввода/вывода или ввода/вывода Завершение порта), код может либо:

  1. (блокировка) вызывает accept() или WSAAccept() и блокирует его до тех пор, пока он не получит соединение из очереди.

  2. (без блокировки) использовать select(), WSAAsyncSelect() или WSAEventSelect() получать уведомления, когда соединение готово и ждет, чтобы получить с accept() или WSAAccept().

  3. (overlapped/iocp) call AcceptEx(), чтобы начать асинхронное принятие, а затем ждать уведомления о событии/завершении, указывающего, что соединение было получено из очереди.

+0

Думаю, у меня это есть. Таким образом, представляя черный ящик, который является системой поставщика, поставщик скорее всего сидит на 'select()' вместо 'listen()'. Итак, точка 2, когда соединение «готово и ждет». , , это означает, что рукопожатие завершено? Клиент отправил TCP ACK? Или он все еще может «быть готовым и ждать» в ожидании конечного клиента ACK? –

+1

Как я сказал в своем ответе: «* Только ** полностью установленные ** соединения доступны для' accept() ', ... *". Так что да, квитирование связи должно быть завершено до того, как код когда-либо увидит соединение. –

+0

Спасибо Реми. Очень ценится. Это означает, что полуоткрытое соединение не повреждает службу, поэтому должно быть что-то отправлено службе. Но мы просто не можем определить, что это такое. Теперь, когда я понимаю, как 'listen()', 'select()' и 'accept()' работают вместе и с стек протоколов, я буду продолжать искать. Еще раз спасибо! –

0

В какой момент слушать сообщить службе есть новое соединение, готовой быть принят?

Никогда.

Должно ли быть установлено соединение TCP до того, как прослушивание передаст его службе, которая будет принята? Или серверу просто нужно вернуть SYN/ACK, прежде чем он сообщит службе?

Ничего из этого не происходит. listen() просто помещает сокет в состояние LISTEN и заставляет TCP начинать принимать соединения и помещать их в очередь на отставание. Это accept(), который связывается с сервисом: он блокируется, когда очередь на обратном пути пуста (по существу), а затем возвращает первую запись и создает вокруг нее новый сокет.

Если рукопожатие должно быть полным - SYN, SYN/ACK, ACK - перед тем, как прослушивание сообщит службе, тогда я могу пойти по неправильному пути.

Он должен быть завершен до того, как accept() вернет новый разъем для обслуживания.

Если сокету просто нужно добраться до SYN/ACK, может возникнуть проблема с обработкой службы неполного сеанса.

Не проблема. Он не ведет себя так.

Другие испытания, когда мы завершаем сеанс TCP и отправляем поддельные данные, пытающиеся вызвать службу для сбоя - не привели к сбою службы.

QED.

Но повторное тестирование nmap довольно надежно сбрасывает его, поэтому я склоняюсь к проблеме полуоткрытого соединения.

Пожалуйста, определите 'crashing'.

+0

Поставщик услуг, поэтому не может быть явным для «сбоев». «Заблокировать» может быть лучший термин, но мы не можем точно знать. Нет записей в журнале.Элементы управления камерой серые на экранах клиентов и серверов, неспособные переместить камеру, иногда камера будет случайно указывать в другом направлении при сбое. Перезапуск службы PTZ работает 4 раза в 5 раз; в других случаях сервер требует перезагрузки. Продавец говорит, что сканирование портов вызывает проблемы. Мы пытаемся установить точные обстоятельства и причины, чтобы мы могли сообщить поставщику Fix Your Stuff. –

Смежные вопросы