Discussion:
bind(): Address already in use
(слишком старое сообщение для ответа)
Pavel Gulchouck
2014-02-01 10:24:10 UTC
Permalink
Hi All!

Есть сетевой демон, который по сигналу перечитывает конфиг.
В конфиге написан адрес/порт, который он слушает. Соответственно, он закрывает
слушающий сокет, перечитывает конфиг, и биндит его заново, с новыми значениями.
Иногда (нечасто, один раз на ~тысячу рестартов) bind() возвращает ошибку,
EADDRINUSE.
Почему это происходит и как правильно с этим бороться?
Вариант не перебиндивать сокет, если адрес/порт не поменялся, мне почему-то не
нравится, кажется заплаткой.
Проявляется в multithread-версии, т.е. вариант, что сокет унаследовался и
остался открыт ребёнком, вроде как, исключается.
Linux.

Lucky carrier,
Паша
aka ***@gul.kiev.ua
Valentin Nechayev
2014-02-01 12:54:30 UTC
Permalink
PG> Есть сетевой демон, который по сигналу перечитывает конфиг.
PG> В конфиге написан адрес/порт, который он слушает.

TCP, UDP, другое?

PG> Соответственно, он закрывает
PG> слушающий сокет, перечитывает конфиг, и биндит его заново, с новыми значениями.
PG> Иногда (нечасто, один раз на ~тысячу рестартов) bind() возвращает ошибку,
PG> EADDRINUSE.
PG> Почему это происходит и как правильно с этим бороться?

SO_REUSEADDR ставится на сокет перед биндингом?

PG> Вариант не перебиндивать сокет, если адрес/порт не поменялся, мне почему-то не
PG> нравится, кажется заплаткой.
PG> Проявляется в multithread-версии, т.е. вариант, что сокет унаследовался и
PG> остался открыт ребёнком, вроде как, исключается.
PG> Linux.


--netch--
Pavel Gulchouck
2014-02-01 11:02:42 UTC
Permalink
Hi Valentin!

01 Feb 14, Valentin Nechayev ==> Pavel Gulchouck:

PG>> Есть сетевой демон, который по сигналу перечитывает конфиг.
PG>> В конфиге написан адрес/порт, который он слушает.

VN> TCP, UDP, другое?

TCP.

PG>> Соответственно, он закрывает
PG>> слушающий сокет, перечитывает конфиг, и биндит его заново, с новыми
PG>> значениями.
PG>> Иногда (нечасто, один раз на ~тысячу рестартов) bind() возвращает ошибку,
PG>> EADDRINUSE.
PG>> Почему это происходит и как правильно с этим бороться?

VN> SO_REUSEADDR ставится на сокет перед биндингом?

Да, ставится.

PG>> Вариант не перебиндивать сокет, если адрес/порт не поменялся, мне
PG>> почему-то не
PG>> нравится, кажется заплаткой.
PG>> Проявляется в multithread-версии, т.е. вариант, что сокет унаследовался и
PG>> остался открыт ребёнком, вроде как, исключается.
PG>> Linux.

Lucky carrier,
Паша
aka ***@gul.kiev.ua
Serguei E. Leontiev
2014-02-01 13:26:07 UTC
Permalink
Привет Pavel,

От 1 февраля 2014 г., 15:02:42 в fido7.ru.unix.prog ты писал:
PG>>> возвращает ошибку, EADDRINUSE.
PG>>> Почему это происходит и как правильно с этим бороться?
VN>> SO_REUSEADDR ставится на сокет перед биндингом?
PG> Да, ставится.

Есть ещё один магический лом: SO_REUSEPORT

--
Успехов, Сергей Леонтьев. E-mail: ***@CryptoPro.ru
Serguei E. Leontiev
2014-02-01 14:14:45 UTC
Permalink
Привет Pavel,

От 1 февраля 2014 г., 15:02:42 в fido7.ru.unix.prog ты писал:
PG>>> возвращает ошибку, EADDRINUSE.
PG>>> Почему это происходит и как правильно с этим бороться?
VN>> SO_REUSEADDR ставится на сокет перед биндингом?
PG> Да, ставится.

Значит не потому, что остались соединения в TIME_WAIT. Похоже на то, что
все стали ходить по одним граблям :)

PG>>> Вариант не перебиндивать сокет, если адрес/порт не
PG>>> поменялся, мне почему-то не
PG>>> нравится, кажется заплаткой.
PG>>> Проявляется в multithread-версии, т.е. вариант, что
PG>>> сокет унаследовался и остался открыт ребёнком, вроде
PG>>> как, исключается.

Hу, дети они такие, их могут порождать и библиотечные функции, а они всё
равно будут наследовать если нет FD_CLOEXEC.

"*CLOEXEC об"
http://fido7.ru.unix.prog.narkive.com/Guv1agdD/cloexec

PG>>> Linux.

Бывает и вот так:
"Безумные сокеты и параллельное чтение с закрытием"
http://fido7.ru.unix.prog.narkive.com/zgYKoA0S

Подозреваю, что в Linux и параллельный accept() может обладать
аналогичным эффектом.


--
Успехов, Сергей Леонтьев. E-mail: ***@CryptoPro.ru
Pavel Gulchouck
2014-02-02 05:49:54 UTC
Permalink
Hi Serguei!

01 Feb 14, Serguei E. Leontiev ==> Pavel Gulchouck:

SEL> От 1 февраля 2014 г., 15:02:42 в fido7.ru.unix.prog ты писал:
PG>>>> возвращает ошибку, EADDRINUSE.
PG>>>> Почему это происходит и как правильно с этим бороться?
VN>>> SO_REUSEADDR ставится на сокет перед биндингом?
PG>> Да, ставится.

SEL> Значит не потому, что остались соединения в TIME_WAIT. Похоже на то, что
SEL> все стали ходить по одним граблям :)

PG>>>> Вариант не перебиндивать сокет, если адрес/порт не
PG>>>> поменялся, мне почему-то не
PG>>>> нравится, кажется заплаткой.
PG>>>> Проявляется в multithread-версии, т.е. вариант, что
PG>>>> сокет унаследовался и остался открыт ребёнком, вроде
PG>>>> как, исключается.

SEL> Hу, дети они такие, их могут порождать и библиотечные функции, а они всё
SEL> равно будут наследовать если нет FD_CLOEXEC.

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

Если не поможет - буду пробовать другие варианты (REUSEPORT, shutdown(),
ожидание).
Спасибо.

Lucky carrier,
Паша
aka ***@gul.kiev.ua
Serguei E. Leontiev
2014-02-01 13:15:34 UTC
Permalink
Привет Pavel,

От 1 февраля 2014 г., 14:24:10 в fido7.ru.unix.prog ты писал:
PG> Есть сетевой демон, который по сигналу перечитывает конфиг.
PG> В конфиге написан адрес/порт, который он слушает.
PG> Соответственно, он закрывает слушающий сокет, перечитывает
PG> конфиг, и биндит его заново, с новыми значениями. Иногда
PG> (нечасто, один раз на ~тысячу рестартов) bind() возвращает
PG> ошибку, EADDRINUSE. Почему это происходит и как правильно с
PG> этим бороться?

RTFM, Яндекс? TCP соединения ещё не прекратили своего существования (они
живут некоторое время после close() в состоянии TIME_WAIT).

PG> Вариант не перебиндивать сокет, если адрес/порт
PG> не поменялся, мне почему-то не нравится, кажется заплаткой.

Хм. А ты что, при смене конфигурации соединения закрываешь, для
надёжности? Hет, ну если тебе важна надёжность, то способ только один:
при ошибке EADDRINUSE подождать некоторое время и повторить (какое время
ждать, можно узнать у системы - RTFM).

Хотя, некоторые "бандерлоги" используют другую, достаточно опасную
заплатку - SO_REUSEADDR, а потом удивляются, что их демон по ошибке
цапнул 22 порт (23, 443, 3389 и т.п.), они естественно ничего не
заметили, а вот на следующий день - неожиданность: не могут связаться с
системой.

RTFM и Яндекс в помощь, родной.

--
Успехов, Сергей Леонтьев. E-mail: ***@CryptoPro.ru
Eugene Grosbein
2014-03-21 18:59:14 UTC
Permalink
01 фев 2014, суббота, в 17:15 NOVT, Сергей Ефимович Леонтьев написал(а):

СЕЛ> Хотя, некоторые "бандерлоги" используют другую, достаточно опасную
СЕЛ> заплатку - SO_REUSEADDR, а потом удивляются, что их демон по ошибке
СЕЛ> цапнул 22 порт (23, 443, 3389 и т.п.), они естественно ничего не
СЕЛ> заметили, а вот на следующий день - неожиданность: не могут связаться с
СЕЛ> системой.

А можно поподробнее этот сценарий расписать?

Eugene

Loading...