2008-10-02 2 views
11

Возможно ли разблокировать сокет после того, как вы вызвали прослушивание (fd, backlog)?Возможно ли разблокировать гнездо?

Редактировать: Моя ошибка за то, что я не поняла. Я хотел бы временно временно отключить сокет. Вызов функции close() оставит сокет в состоянии M2LS и не позволит мне его повторно открыть (или, что еще хуже, какая-то гнусная программа может привязываться к этому гнезду)

Временное неупорядочение было бы способом (может быть, не лучшим) для сигнала к вышерасположенному балансовому балансовому оператору, что к этому оператору больше не добавлено запросов.

ответ

3

Некоторые библиотеки сокетов позволяют специально отклонять входящие соединения. Например: GNU's CommonC++: TCPsocket Class имеет метод reject.

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

while (running) { 

    int i32ConnectFD = accept(i32SocketFD, NULL, NULL); 
    while (noConnectionsPlease) { 
    shutdown(i32ConnectFD, 2); 
    close(i32ConnectFD); 
    break; 
    } 

} 
4

Закройте его. Как я помню;

close(fd); 
1

Существует нет явного метода unlisten!

Вы можете close(fd) или shutdown(fd, how)

fd is the socket file descriptor you want to shutdown, and how is one of the following: 

0 Further receives are disallowed 

1 Further sends are disallowed 

2 Further sends and receives are disallowed (like close()) 
+0

shutdown() может быть разрешен, но единственные значения, которые я ожидал получить, будут 0 или 2, что в любом случае остановит всю полезность в слуховом соке. close() проще и более чем достаточно явным, особенно в (я предполагаю) C. – 2008-10-02 12:01:56

5

После закрытия сокета, ваши программы могут еще сказать вам, что сокет «используется», то это из-за какой-то weirdiness я не знаю точно о , Но справочная информация о сокетах показывает, что есть флаг для повторного использования одного и того же сокета, лениво называемого: «SO_REUSEADDR». Установите его, используя «setsockopt()».

+1

Я не уверен, но я думаю, что если вы отключите опцию SO_LINGER с помощью setsockopt(), это может помочь в этом. – Ferruccio 2008-10-02 14:43:09

0

На базовом уровне сокеты являются открытыми или закрытыми (здесь мы проигнорируем тонкости схемы состояния TCP/IP).

Если ваш разъем закрыт, ничто не может отправить данные на него. Если он открыт, то входящие данные будут приняты и подтверждены стеком TCP/IP до тех пор, пока алгоритм буферизации не будет кричать «достаточно!». В этот момент дальнейшие данные не будут признаны.

У вас есть два варианта, которые я могу видеть. Либо соедините() сокет, когда вы хотите «unlisten», и снова его открыть. - Используйте setsockopt() с флагом SO_REUSEADDR, чтобы вы могли повторно привязываться к известному порту до истечения срока действия TIME_WAIT2.

Другой выбор заключается в том, чтобы держать сокет открытым, но просто не принимать() от него, пока вы «заняты». Предполагая, что у вас есть подтверждение на уровне приложения для запросов, вы балансировщик нагрузки понимаете, что он не получает ответа и действует соответствующим образом.

2

Основываясь на вашей отредактированной версии вопроса, я не уверен, что вам нужно «unlisten» или close(). Вам приходят в голову два варианта:

1) После того, как вы вызываете listen(), соединения фактически не принимаются до (логически достаточно), которые вы вызываете accept(). Вы можете «unlisten» просто проигнорировать активность сокета и отложить любой accept() до тех пор, пока вы не будете готовы к ним. Любое входящее соединение пытается создать резервную копию в очереди, которая была создана при открытии порта в режиме прослушивания. Как только очередь задержек заполнена в стеке, дальнейшие попытки соединения просто отбрасываются на пол. Когда вы возобновляете с accepts(), вы быстро деактивируете отставание и будьте готовы к большему количеству подключений.

2) Если вы действительно хотите, чтобы порт отображался полностью закрытым временно, вы можете динамически применить фильтр пакетов уровня ядра к порту, чтобы предотвратить попытки входящего подключения в сетевой стек. Например, вы можете использовать фильтр пакетов Berkeley (BPF) на большинстве платформ * nix. То есть вы хотите удалить входящие пакеты, входящие в порт интереса, используя функции брандмауэра платформы. Это, конечно, зависит от платформы, но это возможный подход.

+0

Проблема с сохранением этих подключений в записях accept(), даже если вы не принимаете() их вверх, у верхнего уровня LB нет возможности узнать вашу очередь в очереди (не обрабатывать запросы) Одна из идей может заключаться в том, чтобы установить backlog до 1, поэтому после того, как запрос будет поставлен в очередь, последующие будут сбой – 2008-10-02 21:51:45

+0

(почему комментарии ограничены 300 символами?), чтобы продолжить, что возвращает на мой сервер ответственность за регулярное очищение журнала accept(), но это это то, что будет происходить в идеальных условиях, и в менее идеальных условиях LB, получающий E_CONNREFUSED, избежит очереди в очереди – 2008-10-02 21:53:17

0

Вот довольно некрасиво подход, основанный на отредактированном вопрос:

Открыть сокет для прослушивания нормального отставания. Приступить.

Когда вы хотите «выключить», откройте 2-й из них с отставанием 1 и SO_REUSEADDR. Закройте первый. Когда вы будете готовы к возобновлению, выполните другой манипулятор сокета с одним из них с нормальным отставанием.

В этом случае убийца будет убивать приемную очередь из сокета, который вы закрываете. Вероятно, достаточно убийцы, чтобы сделать этот подход нежизнеспособным.

0

Я не обязательно думать, что это хорошая идея, но ...

Вы могли бы быть в состоянии вызвать прослушивание второй раз. Спецификация POSIX не говорит об этом. Возможно, вы могли бы назвать это во второй раз с параметром backlog 0, когда вы хотите «unlisten».

Что происходит, когда прослушивание вызывается с отставанием 0, представляется, что реализация определена. Спецификация POSIX говорит, что может разрешить соединения, которые предполагают, что некоторые реализации могут отклонить все соединения, если параметр backlog равен 0. Вероятнее всего, ваша реализация выберет некоторое положительное значение, когда вы пройдете в 0 (возможно, либо 1 или SOMAXCONN).

2

Я не думаю, что это хороший способ сигнализировать балансировку нагрузки вверх. Это должно было бы фактически отправить некоторые подключения к вашему серверу до того, как сообщение получилось - эти соединения, вероятно, будут отвергнуты.

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

Если вы хотите сигнализировать о балансировке нагрузки вверх, у вас должен быть протокол для этого. Не пытайтесь использовать TCP для этого.

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

0

Вопрос не сказал, какой разъем. Если это unix-сокет, вы можете остановить и начать прослушивание с помощью переименования (2). Вы также можете навсегда прекратить прослушивание с помощью функции unlink (2), а так как сокет остается открытым, вы можете продолжить обслуживание своего отставания. Этот подход кажется весьма удобным, хотя я не видел его раньше, и просто изучал его сам.

0

У вас уже есть ответы на невозможность сделать это через API сокетов.

Вы можете использовать другие методы ОС (то есть Host firwewall/iptables/ipfilter), чтобы установить правило временного отклонения.

Я обнаружил, что большинство балансировки нагрузки немного ограничен в возможностях, которые они предлагают признать проблемы соединения (большинство из них признает RST только в подключении датчика, а не ответ на законную попытку подключения.)

В любом случае, если вы ограничены зондами, обнаруживающими недоступность, вы настраиваете зонд уровня приложения, который выполняет запрос HTTP или FTP-логин или аналогичные вещи, которые он распознает, если вы просто закроете после принятия. Он может даже интерпретировать сообщения об ошибках, такие как «500 сервис недоступен», что кажется мне чище для меня в любом случае. С SNMP некоторые балансировки нагрузки также могут использовать результат в качестве подсказки загрузки.

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