Подтвердить что ты не робот

Возможно ли разблокировать сокет?

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

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

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

4b9b3361

Ответ 1

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

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

while (running) {

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

}

Ответ 2

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

Ответ 3

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

close(fd);

Ответ 4

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

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

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

Ответ 5

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

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

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

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

Ответ 6

Нет явного метода 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())

Ответ 7

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

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

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

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

Ответ 8

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

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

Если вы хотите "закрыть", откройте второй, у которого есть отставание от 1 и SO_REUSEADDR. Закройте первый. Когда вы будете готовы возобновить работу, выполните еще один жонглирование сокета с тем, у которого есть нормальное отставание.

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

Ответ 9

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

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

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

Ответ 10

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

Ответ 11

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

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

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

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