CodeNet / Языки программирования / C / C++ / Linux/Unix
Перечисление сетевых интерфейсов
Автор: Konstantin Malahov
Источник: www.varkon.biz
В процессе работы твоей программы нередко надо получить список сетевых адресов доступных на данном компьютере, что бы в дальнейшем этот список использовать для своих задач.
Способов как это реализовать существует несколько - и наиболее распространенный - это использовать API операционной системы. Этого вполне хватит за глаза для большинства задач. Правда есть одна проблема - операционных систем много, и Windows - всего лишь одна из них. Есть еще и, так называемое семейство *nix-подобных систем, к которым относится Linux, MacOS и еще множество других. А хороший программист (а ты ведь хороший программист, не так ли) должен учитывать такие нюансы.
Но на самом деле ничего страшного в этом нет. Во первых, есть языки (например Java, Perl, PHP, Python etc), которым вообще не важна ОС - главное что бы, была соответствующая виртуальная машина или интерпретатор. Но об этом позже. Будет настроение - я уделю этим языкам отдельную статью, в связи с тем что это совершенно другая идеология и методы.
Во вторых - ты можешь для каждой системы компилировать необходимый бинарный файл - это не так удобно, как первый вариант - но зато на несколько порядков быстрее и эффективнее. Но после каждого изменения - да, надо снова все перекомпилировать. Нет счастья на земле. Но нет его и выше... Или как сказал другой поет:
Нет счастья на земле.
Ни с Запада, ни с юга
Не увидать его ни в небе, ни в аду...
Мы с каждым днем, увы,
Несчастней друг для друга...
Остановите землю, - я сойду!
Но впрочем оставим романтику бардам, им тоже надо в лесах о чем то петь.
В *nix-подобных системах для получения списка сетевых интерфейсов используется системный вызов ioctl, а в вынодоус - все естественно не так, там для этих целей служит WSAIoctl. И как с этим жить? Да собственно так и живем, ничего страшного. Для этого в C/C++ существует такая замечательная штука как директива условной компиляции #ifdef которая позволяет управлять, что мы включим в код, а что оставим за бортом. Перед компиляцией выполняется специальный проход - препроцессинг, который определяет, что подавать компилятору на обработку, а что выкинуть(или преобразовать) - это называется директивы препроцессора. Что это такое, с чем его едят - читай по ссылке. К теме это не относится.
Дальше собственно код:
Как видишь - сложного в данном коде ничего нет. Все просто. Получаем адреса - и выводим их на экран. Результат работы программы под вындоус выглядит примерно так: под линух Ну либо используем так, как необходимо. На что надо обратить внимание - это размер буфера - BUF_SIZE, если ты компилируешь программу под WIN64 - возможно его надо увеличить. А возможно и нет - экспериментируй и проверяй все на практике. На 64-х разрядной системе это не тестировалось. Естественно, в коде могут быть опечатки - так как набирал его руками - опять же, я полагаю, что если ты берешься за сетевое программирование - то ты имеешь некоторый опыт, по этому проблем иметь не должен. Если такового ты не имеешь - то получи его. В остальном - если будут адекватные вопросы - с удовольствием отвечу. Код предназначен для свободного использования и распространения.
* 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 2dr0zd714# ./hs_lookup
address 0 127.0.0.1
address 1 192.168.2.16
End list address. Seach 2Оставить комментарий
Комментарии
#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 и так с каждым из файлов в чем причина? буду очень благодарна ответу мне очень необходимо получить ответ! заранее спасибо
QList<QHostAddress> AllLocalAddresses = QNetworkInterface::allAddresses();