nginx + default {deferred|bind} = корки

Igor Sysoev is at rambler-co.ru
Wed May 30 09:03:11 MSD 2007


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





More information about the nginx-ru mailing list