Получить неправильный IP-адрес при использовании bind () в C - PullRequest
2 голосов
/ 04 января 2012

Я использую API программирования сокетов в C. В клиентской программе TCP я использую bind(), а затем getsockname() (перед вызовом connect()), чтобы получить IP-адрес и номер порта локальной машины. , Тем не менее, я могу получить только правильный номер порта при получении неправильного IP-адреса (ноль).

Итак, я спрашиваю, есть ли способ правильно получить правильный IP-адрес для локальной машины (до вызова connect())?

Ответы [ 5 ]

4 голосов
/ 04 января 2012

Не существует простого или переносимого способа сделать то, что вы пытаетесь сделать.Поведение bind() и getsockname() в вашем случае правильное.

Ваша программа никоим образом не должна зависеть или требовать IP-адрес хоста.Если это произойдет, возможно, у вас возникла проблема с дизайном в вашей программе.

Спросите себя, каков IP-адрес компьютера с двумя сетевыми интерфейсами, подключенными к двум разным сетям и несколькими IP-адресами?

     Network 1                  Network 2
...-----------+--            --+-----------...
               \              /
     192.0.2.1  \            /  198.51.100.2
          eth0  +------------+  eth1
                |  Computer  |
                +------------+

В: Какой IP-адрес вы ожидаете увидеть в этом случае?

Ответ заключается в том, что нет правильного ответа, и ваша программа не должна даже беспокоиться об этом.Ваша программа должна больше заботиться об установлении связи, и для этого вам нужен только целевой IP или имя хоста.Операционная система найдет способ установить связь (а для потоков, ориентированных на соединение, она может сможет дать вам локальный адрес, выбранный для связи с этой целью).

Вы можете получить текущее имя хоста, используя gethostname(), и с этим именем вы можете попытаться найти IP-адрес, но есть еще много ошибок:

  1. Этоне требуется или не гарантируется, что имя хоста имеет какой-либо связанный IP-адрес.
  2. Во многих случаях, чем вы думаете, IP-адрес, связанный с именем хоста, равен 127.0.0.1, что бесполезно (большинство дистрибутивов Linux добавляют это кваш файл / etc / hosts).
  3. Даже если вы получите IP-адрес от имени хоста, маловероятно, что он будет полезен (как в случае 2 выше, или локальный IP-адрес за NAT,или IP неверного сетевого интерфейса).

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

1 голос
/ 04 января 2012

Если вы привязываетесь к INADDR_ANY, то это адрес, по которому вы получите getsockname().

В частности, на машине с несколькими интерфейсами адрес, используемый вашей стороной сокета, будет зависеть от таблицы маршрутизации и адреса удаленного клиента.

Например, если вы подключитесь к себе через интерфейс обратной связи, вы будете на 127.0.0.1, тогда как, если вы подключитесь к кому-то извне, это будет (один из) адресов вашего интерфейса Ethernet.

Правильный подход в том и только в том случае, если вам действительно необходимо выполнить привязку к известному адресу , это перечислить сетевые интерфейсы вашей машины (см. man netdevice, если вы работаете в Linux), а затем указать конкретный желаемый адрес bind().

1 голос
/ 04 января 2012

Вы можете использовать gethostname для получения имени хоста, а затем использовать gethostbyname для получения IP-адресов.

1 голос
/ 04 января 2012

Переносимый способ сделать это - сначала вызвать gethostname (), а затем вызвать gethostbyname ().

т.

char hostname[256], ipaddress[256];
if (gethostname(hostname, sizeof(hostname)) != SOCKET_ERROR) {
    struct hostent *phe = gethostbyname(hostname);
    if (phe != NULL && phe->h_addr_list[0] != NULL) {
        struct in_addr addr;
        memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));
        strcpy(ipaddress, inet_ntoa(addr));
    }
}
0 голосов
/ 04 января 2012

Вы можете использовать gethostip() для получения IP-адреса хоста.

...