Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Последние темы форума

Показать новые сообщения »

Почтовая рассылка

Подписчиков: 11852
Последний выпуск: 19.06.2015

Перечисление сетевых интерфейсов

Автор: Konstantin Malahov
Источник: www.varkon.biz

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

Способов как это реализовать существует несколько - и наиболее распространенный - это использовать API операционной системы. Этого вполне хватит за глаза для большинства задач. Правда есть одна проблема - операционных систем много, и Windows - всего лишь одна из них. Есть еще и, так называемое семейство *nix-подобных систем, к которым относится Linux, MacOS и еще множество других. А хороший программист (а ты ведь хороший программист, не так ли) должен учитывать такие нюансы.

Но на самом деле ничего страшного в этом нет. Во первых, есть языки (например Java, Perl, PHP, Python etc), которым вообще не важна ОС - главное что бы, была соответствующая виртуальная машина или интерпретатор. Но об этом позже. Будет настроение - я уделю этим языкам отдельную статью, в связи с тем что это совершенно другая идеология и методы.

Во вторых - ты можешь для каждой системы компилировать необходимый бинарный файл - это не так удобно, как первый вариант - но зато на несколько порядков быстрее и эффективнее. Но после каждого изменения - да, надо снова все перекомпилировать. Нет счастья на земле. Но нет его и выше... Или как сказал другой поет:

Нет счастья на земле.
Ни с Запада, ни с юга
Не увидать его ни в небе, ни в аду...
Мы с каждым днем, увы,
Несчастней друг для друга...
Остановите землю, - я сойду!

Но впрочем оставим романтику бардам, им тоже надо в лесах о чем то петь.

В *nix-подобных системах для получения списка сетевых интерфейсов используется системный вызов ioctl, а в вынодоус - все естественно не так, там для этих целей служит WSAIoctl. И как с этим жить? Да собственно так и живем, ничего страшного. Для этого в C/C++ существует такая замечательная штука как директива условной компиляции #ifdef которая позволяет управлять, что мы включим в код, а что оставим за бортом. Перед компиляцией выполняется специальный проход - препроцессинг, который определяет, что подавать компилятору на обработку, а что выкинуть(или преобразовать) - это называется директивы препроцессора. Что это такое, с чем его едят - читай по ссылке. К теме это не относится.

Дальше собственно код:

Код:
/***
*    hs_lookup.c
*   author: k0t aka dr0zd714 aka varkon
*   e-mail: varkonom@gmail.com
*   site: http://varkon.biz
*   for hackersoft.ru
*/

#ifdef WIN32 || WIN64
   #pragma comment(lib,"ws2_32.lib")
   #include <winsock2.h>
#else

    #include <sys/types.h>
    #include <netinet/in.h>
    #include <sys/socket.h>
    #include <sys/ioctl.h>
    #include <arpa/inet.h>
    #include <net/if.h>

#endif
#include <stdio.h>
/***
*
*   lookup_addr_indx()
*
*/

#define BUF_SIZE    4092
int lookup_addr_indx(int indx,
                               unsigned int *addr)
{
#ifdef WIN32 || WIN64
  LPSOCKET_ADDRESS_LIST list = NULL;
  SOCKET  sc = 0;
  char  buf[BUF_SIZE];
  int len = 0;
  int ret = 0;

  sc = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
  if(sc == INVALID_SOCKET){
     return (-1);
  }
  ret = WSAIoctl(sc,
                         SIO_ADDRESS_LIST_QUERY,
                          NULL,
                          0,
                          buf,
                          BUF_SIZE,
                          (unsigned long *)&len,
                          NULL,
                          NULL);
  closesocket(sc);
  if(ret != 0 || len <= 0){
      return(-2);
  }
  list = (LPSOCKET_ADDRESS_LIST) buf;
  if(list->iAddressCount <=0){
     return (-3);
  }
  for(int i = 0; i <= indx && i < list->iAddressCount; ++i){
    //нашли адрес
     if(i == indx){
       memcpy(addr,
                    &list->Address[i].lpSockaddr->sa_data[2],4);
       return (1);
    }
  }
//адресов не осталось
 return (0);
#else
  struct ifconf ifc;
  struct ifreq *ifr = NULL;
  char buf[BUF_SIZE];
  int ret = 0;
  int off = 0;
  int cnt = 0;
  int cdx = 0;
  int sc = 0;
  sc = socket(AF_INET, SOCK_DGRAM, 0);
  if(sc < 0){
    return (-1);
  }
  ifc.ifc_len = BUF_SIZE;
  ifc.ifc_buf = buf;
  ret = ioctl(sc, SIOCGIFCONF, &ifc);
  if(ret <0){
    return (-2);
  }
  ifr = ifc.ifc_req;
  while(cnt < ifc.ifc_len && cdx <= indx){
    if(ifr->ifr_addr.sa_family == AF_INET){
       if(cdx == indx){
          memcpy(addr, &ifr->ifr_addr.sa_data[2], 4);
          return (1);
       }
     ++cdx;
    }
  off = IFNAMSIZ + ifr->ifr_addr.sa_len;
  cnt += off;
  ((char*) ifr) += off;
  }
 close(sc);
#endif
 return (0);
}
int main(void)
{
 #ifdef WIN32 || WIN64
    WSADATA wsa;
 #endif

  struct in_addr ia;
 unsigned int addr = 0;
 int ret = 0;
 int idx = 0;
 #ifdef WIN32 || WIN64
  memset(&wsa, 0x0, sizeof(WSADATA));
  if(WSAStartup(MAKEWORD(2, 0), &wsa) != 0x0){
    printf("WSAStartup error! \n");
    return (1);
  }

 #endif
 while(1){
  ret = lookup_addr_indx(idx, &addr);
  if(ret < 0){
    printf("lookup_addr_indx error. Code %d \n", ret);
    return (1);
  }
  else if(ret == 0){
    break;
  }
  ia.s_addr = addr;
  printf("address %d: %s\n", idx, inet_ntoa(ia));
  ++idx;
  printf("End list address. Seach %d\n", idx);
  return (0);
 }
}

Как видишь - сложного в данном коде ничего нет. Все просто. Получаем адреса - и выводим их на экран. Результат работы программы под вындоус выглядит примерно так:

D:\Progects\mingw\hs_lookup\bin\hs_lookup.exe
address 0 192.168.1.100
address 1 192.168.2.12
End list address. Seach 2

под линух

dr0zd714# ./hs_lookup
address 0 127.0.0.1
address 1 192.168.2.16
End list address. Seach 2

Ну либо используем так, как необходимо. На что надо обратить внимание - это размер буфера - BUF_SIZE, если ты компилируешь программу под WIN64 - возможно его надо увеличить. А возможно и нет - экспериментируй и проверяй все на практике. На 64-х разрядной системе это не тестировалось. Естественно, в коде могут быть опечатки - так как набирал его руками - опять же, я полагаю, что если ты берешься за сетевое программирование - то ты имеешь некоторый опыт, по этому проблем иметь не должен. Если такового ты не имеешь - то получи его.

В остальном - если будут адекватные вопросы - с удовольствием отвечу. Код предназначен для свободного использования и распространения. 

Оставить комментарий

Комментарий:
можно использовать BB-коды
Максимальная длина комментария - 4000 символов.
 

Комментарии

1.
92K
04 декабря 2013 года
Татьяна Волкова
0 / / 04.12.2013
Мне нравитсяМне не нравится
4 декабря 2013, 12:44:20
Решила попробовать ваш код мне очень необходима определить количество сетевых интерфейсов и вот ваш код очень подходит но я не могу его запустить у меня выдает ошибки что не может подключить файл включения то есть вот эти файлы он не может подключить!

Код:
#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/ioctl.h>

#include <arpa/inet.h>

#include <net/if.h>

не подскажете как это исправить? ошибку пишет вот такую: error C1083: Не удается открыть файл включение: netinet/in.h: No such file or directory и так с каждым из файлов в чем причина? буду очень благодарна ответу мне очень необходимо получить ответ! заранее спасибо
2.
91K
26 июля 2013 года
Сергей Шумейко
0 / / 26.07.2013
+2 / -0
Мне нравитсяМне не нравится
26 июля 2013, 16:22:43
А еще можно так (ну, если используешь Qt):

QList<QHostAddress> AllLocalAddresses = QNetworkInterface::allAddresses();
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог