On Wed, May 30, 2007 at 01:14:26AM +0300, Alex Vorona wrote:
> Igor Sysoev пишет:
> >On Tue, May 29, 2007 at 07:57:56PM +0400, Александр Ворона wrote:
> >
> >>Igor Sysoev пишет:
> >>
> >>>FreeBSD позволяет bind() to 127.0.0.1:80 и *:80 в любом порядке.
> >>>Насчёт Линукса - нужно проверить.
> >>>
> >>netstat -tnepl|grep cfg.txt
> >>tcp 0 0 0.0.0.0:82 0.0.0.0:*
> >> LISTEN 0 85904536 19582/cfg.txt
> >>
> >>нет bind() на 127.0.0.1:82
> >
> >У меня воспроизводится эта ошибка, причём даже для такого непересекающегося
> >варианта:
> >
> > listen 127.0.0.1:8000 default bind;
> > listen 192.168.1.1:8000 default bind;
> >
> >Второй listen всегда вылетает с ошибкой (98: Address already in use).
> >Проверялось на ядре 2.6.16.13.
>
> 2.6.9 с ipv6 - на разных ИП без проблем.
> Попробовал
>
> server {
> listen 127.0.0.1:82 default bind;
> }
>
> server{
> listen 82 default bind;
> }
> вообще хорошо - воркер быстренько нагнал мне 300М логов вида
>
> accept() failed (22: Invalid argument) while accepting new connection on
> 0.0.0.0:82
> Причём первой строчкой была
> 2007/05/29 16:30:40 [alert] 23161#0: changing the listen() backlog to -1
> for 0.0.0.0:82 failed, ignored (98: Address already in use)
>
> strace
> socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 9
> setsockopt(9, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
> ioctl(9, FIONBIO, [1]) = 0
> bind(9, {sa_family=AF_INET, sin_port=htons(82),
> sin_addr=inet_addr("127.0.0.1")}, 16) = 0
> socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 10
> setsockopt(10, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
> ioctl(10, FIONBIO, [1]) = 0
> bind(10, {sa_family=AF_INET, sin_port=htons(82),
> sin_addr=inet_addr("0.0.0.0")}, 16) = 0
> listen(9, 4294967295) = 0
> listen(10, 4294967295) = -1 EADDRINUSE (Address already in
> use)
> write(4, "2007/05/29 16:38:45 [alert] 2327"..., 133) = 133
>
> те 2 default bind на пересекающихся диапазонах IP:port не привели ни к чему
> хорошему, кроме того, listen на 127.0.0.1:port блокирует последующий listen
> на *:port
>
> >Здесь есть две странности:
> >1) эта ошибка должна по идее выдаваться ещё на стадии bind(),
> >2) эта ошибка не должна выдаваться для непересекающихся адресов (по крайней
> > мере, во FreeBSD с этим не возникает никаких проблем).
> >
> >Есть подозрение на присутствие в ядре ipv6 (хотя nginx о нём не
> >подозревает).
> >
> >Можно попробовать собрать ядро без ipv6 ?
> >
>
> 2.6.20.3 x86_64 и было без ipv6
>
> на непересекающихся ИП ошибки нет
>
> А во FreeBSD при listen на пересекающихся ИП подключение приходит на более
> точный bind из двух возможных?
Да. Можно, например, повесить Апач на 127.0.0.1:80, а nginx - на *:80.
> man 7 socket в Linux
> SO_REUSEADDR
> Indicates that the rules used in validating addresses supplied in a bind(2)
> call should allow reuse of local addresses. For PF_INET sockets this means
> that a socket may bind, except when there is an active listening socket
> bound to the address. When the listening socket is bound to INADDR_ANY
> with a specific port then it is not possible to bind to this port for any
> local address.
>
> Вот как раз и имеем ту ситуацию, с которой начался тред.
Проблема в том, что bind() вопреки этому man'у как раз проходит без ошибок,
а ошибка выплывает только на этапе listen(). И непонятно, почему в этом
случае listening сокет постоянно сообщает о готовых соединениях, а
accept() постоянно вылетает с ошибкой.
--
Игорь Сысоев
http://sysoev.ru