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

Как узнать, связан ли какой-либо процесс с доменным сокером Unix?

Я пишу сервер сокетов домена Unix для Linux.

Особенность сокетов домена Unix, которую я быстро обнаружил, заключается в том, что при создании прослушивающего сокета Unix создается соответствующая запись файловой системы, закрытие сокета не удаляет ее. Более того, до тех пор, пока запись файловой системы не будет удалена вручную, невозможно снова bind() сокет на тот же путь: bind() не работает с EADDRINUSE, если указанный путь уже существует в файловой системе.

Как следствие, запись файловой системы сокета должна быть unlink() 'ed при завершении работы сервера, чтобы избежать перезапуска EADDRINUSE при перезапуске сервера. Однако это не всегда можно сделать (например: авария сервера). Большинство часто задаваемых вопросов, сообщения на форуме, Q & Веб-сайты, которые я нашел, только советуют, как обходной путь, к unlink() сокету до вызова bind(). В этом случае, однако, становится желательным знать, связан ли процесс с этим сокетом до unlink() '.

В самом деле, unlink() в Unix-сокете, пока процесс все еще привязан к нему, а затем повторное создание прослушивающего сокета не вызывает никакой ошибки. В результате, однако, старый серверный процесс все еще работает, но недоступен: старый прослушивающий сокет "замаскирован" новым. Этого поведения следует избегать.

В идеале, используя сокеты домена Unix, API сокета должен иметь одно и то же поведение "взаимного исключения", которое отображается при привязке сокетов TCP или UDP: "Я хочу привязать сокет S к адресу A, если процесс уже связан на этот адрес, просто пожалуйте!" К сожалению, это не так...

Есть ли способ принудить это поведение "взаимного исключения"? Или, учитывая путь файловой системы, есть ли способ узнать через API сокетов, имеет ли какой-либо процесс в системе доменный сокет Unix, связанный с этим путем? Должен ли я использовать примитив синхронизации, внешний по отношению к API сокета (flock(),...)? Или я что-то упускаю?

Спасибо за ваши предложения.

Примечание: абстрактное пространство имен Linux для UNIX-сокетов, похоже, решает эту проблему, так как нет записи файловой системы в unlink(). Однако сервер, который я пишу, должен быть общим: он должен быть устойчивым к обоим типам сокетов домена Unix, поскольку я не несу ответственности за выбор адресов для прослушивания.

4b9b3361

Ответ 1

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

Когда вы сталкиваетесь с возвратом EADDRINUSE из bind(), вы можете ввести процедуру проверки ошибок, которая подключается к сокету. Если соединение завершается успешно, существует текущий процесс, который, по меньшей мере, достаточно велик, чтобы выполнить accept(). Это кажется мне самым простым и самым переносимым способом достижения того, чего вы хотите достичь. У этого есть недостатки в том, что сервер, который создал UDS, в первую очередь, может по-прежнему работать, но "застрял" каким-то образом и не смог сделать accept(), поэтому это решение, безусловно, не является безупречным, но это шаг в правильном направлении, я думаю.

Если connect() не работает, тогда и unlink() конечную точку и снова попробуйте bind().

Ответ 2

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

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

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

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

Существует мало что можно сделать AFAIK для управления другими программами, создающими конфликты. Разрешения для файлов не идеальны, но если опция доступна для вас, вы можете разместить свое приложение в своем собственном пользователе/​​группе. Если существует существующий путь к соке, и вы его не владеете, не отключайте его и не выставляйте сообщение об ошибке и не позволяете пользователю или системному администратору его сортировать. Использование файла конфигурации, чтобы сделать его легко изменяемым и доступным для клиентов, может работать. Кроме того, вы почти должны пойти на какую-то услугу обнаружения, которая кажется массивной перегрузкой, если это не очень важное приложение.

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