Назад | Перейти на главную страницу

Почему я не могу выполнить привязку к 127.0.0.1 в Mac OS X?

Я пытаюсь настроить простой веб-сервер в Mac OS X, но при запуске постоянно получаю сообщение об ошибке bind. Вот что я использую (в этой записи используется GNU Guile, но просто как удобный интерфейс для posix).

(define addr (inet-aton "127.0.0.1"))                     ; get internal representation of 127.0.0.1
(define sockaddr (make-socket-address AF_INET addr 8080)) ; make a struct sockaddr
(define sock (socket PF_INET SOCK_STREAM 0))              ; make a socket
(bind sock sockaddr)                                      ; bind the socket to the address

Это дает мне ошибку In procedure bind: can't assign requested address.

Я попробовал еще раз, разрешив любой адрес.

(define anyaddr (make-socket-address AF_INET INADDR_ANY 8080)) ; allow any address
(bind sock anyaddr)

И это прекрасно работает. Но это странно, потому что ifconfig lo0 говорит

lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
  inet6 ::1 prefixlen 128 
  inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1 
  inet 127.0.0.1 netmask 0xff000000 

Таким образом, устройство обратной связи назначается 127.0.0.1. Итак, мой вопрос: почему я не могу привязаться к этому адресу?

Спасибо.

Обновление: вывод route get 127.0.0.1 является

   route to: localhost
destination: localhost
  interface: lo0
      flags: <UP,HOST,DONE,LOCAL>
 recvpipe  sendpipe  ssthresh  rtt,msec    rttvar  hopcount      mtu     expire
   49152     49152         0         0         0         0     16384         0 

Это не совсем ответ, поскольку он не решает напрямую вашу проблему ... но похоже, что ваша проблема связана с лукавством. То есть в моей системе OS X 10.6 у меня такая же проблема, как и при использовании кода хитрости из вашего примера. С другой стороны, отлично работает следующее:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('127.0.0.1', 8080))
s.listen(5)

c, addr = s.accept()
c.send('hello\n')
c.close()

Если я запускаю этот код, я вижу, что сокет слушает:

netstat -f inet -an | grep 8080
tcp4       0      0  127.0.0.1.8080         *.*                    LISTEN

И подключение к порту 8080 делает то, что вы ожидаете:

$ telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello
Connection closed by foreign host.

В самом деле, в моем случае проблема связана с неинициализированными полями в структуре, которые не имеют ничего общего с семантическим адресом сокета.

Я добавил memset(&sa, 0, sizeof sa) и теперь это связывает.

Почти наверняка реализация Guile столкнулась с той же проблемой: инициализация только задокументированных полей struct sockaddr_in. В любом случае симптомы были точно такие же: INADDR_ANY обязательный, но INADDR_LOOPBACK отказ с тем же errno.

Изменить: извините, если я не понимаю; Я имею в виду то, что я добавил к вопросу, который кто-то удалил. А именно, я столкнулся с точно такой же проблемой при реализации (по чистой случайности) другого диалекта Лиспа. Я добавил свои наблюдения, а также некоторые gdb трассировки сеанса отладки, показывающие содержимое struct sockaddr_in перед bind вызов. Адрес правильно инициализирован sin_family, sin_addr и sin_port поля. Однако sin_len поле во главе структуры (присутствует на Дарвине, отсутствует на других платформах) не инициализировано, а также sin_zero массив заполнения в конце.