Можно ли разлочить на сокете? - PullRequest
13 голосов
/ 02 октября 2008

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

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

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

Ответы [ 11 ]

5 голосов
/ 02 октября 2008

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

4 голосов
/ 04 октября 2008

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

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

while (running) {

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

}
4 голосов
/ 02 октября 2008

Закройте его. Насколько я помню;

close(fd);
2 голосов
/ 13 августа 2010

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

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

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

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

2 голосов
/ 03 октября 2008

Исходя из вашей отредактированной версии вопроса, я не уверен, что вам нужно "не прослушать" или закрыть (). На ум приходят два варианта:

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

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

1 голос
/ 02 октября 2008

Нет явного способа отказаться от прослушивания!

Вы можете либо 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 голосов
/ 08 сентября 2012

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

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

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

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

0 голосов
/ 05 октября 2010

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

0 голосов
/ 09 июля 2009

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

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

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

0 голосов
/ 03 октября 2008

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

Открыть сокет для прослушивания с обычным отставанием. Действуйте.

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

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

...