
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.97.9.172] |
![]() |
|
![]() |
![]() |
|
Часто возникают вопросы такого типа:
- А как получить IP-адрес? - А как установить IP-адрес? - А как узнать, какие сетевые интерфейсы есть в системе? Многие по ошибке лезут в реестр и правят там все руками. Однако сие - не есть правильно. Предлагаю вариант правильный. Он отвечает на вопросы №1 и №3. По вопросу №2 будут комментарии после. Итак, предлагаемый пример для изучения в аттаче. Рассмотрим его. Всю необходимую информацию, а также возможность ее изменить, нам предоставляет библиотека IpHlpApi.dll. Ей и воспользуемся (отметим то, что диалог изменения параметров интерфейсов в WINDOWS пользуется иными средствами - недокументированными, но нам это на данный момент знать не надо. Исследователи и любопытные могут сами посмотреть, что там происходит и рассказать нам об этом. Будем пользоваться средствами стандартными). Итак, подключим необходимые хидеры: ![]() ![]() #include <iphlpapi.h> Необходимо и в свойствах линкера добавить библиотеку iphlpapi.lib. Функция, которая возвращает основную информацию по адаптерам: GetIfTable. Она нам покажет все имеющиеся в системе адаптеры и полезную информацию по ним. (см. ниже). Она нам вернет имена адаптеров, сколько байтов и куда ушло, тип, статус и скорость интерфейсов. Итак, получаем необходимую информацию: 1. Сперва спросим ее, сколько памяти нам нужно под необходимые данные: ![]() ![]() MIB_IFROW mbrow = { 0 }; PMIB_IFTABLE pTable = NULL; DWORD dwSize = 0; if ( GetIfTable( pTable, &dwSize, FALSE ) == ERROR_INSUFFICIENT_BUFFER ) { // ... 2. Получаем в dwSize необходимый для буфера размер и теперь выделяем память под него и выдергиваем инфу: ![]() ![]() pTable = PMIB_IFTABLE(LocalAlloc(LMEM_ZEROINIT, dwSize)); if ( !GetIfTable( pTable, &dwSize, TRUE ) ) { printf("Total entries: %d\nEnumerating...\n", pTable->dwNumEntries); 3. Получили? Начинаем перечислять (вся информация хранится в полученном буфере в виде массива структур): ![]() ![]() for(unsigned int i = 0; i < pTable->dwNumEntries; ++i) { PMIB_IFROW ifRow = &pTable->table[i]; 4. Итак. Что у нас там интересного? Ну, во-первых, описание интерфейса. Его и отображаем: ![]() ![]() char str[MAXLEN_IFDESCR + 1] = { 0 }; CharToOemA((char*) ifRow->bDescr, (char*) ifRow->bDescr); printf("- if%d is:\n\t%s\n", i, ifRow->bDescr); 5. Описание хранится в ANSI формате, поэтому не будем заморачиваться на тему проекта в UNICODE. Затем, нам интересен типа интерфейса. Что это? ЛВС? VPN? Или еще что? А также в каком статусе пребывает? Подключен? Подключается? Или вовсе не работает? ![]() ![]() printf("\tType: %s\n", get_iface_type(ifRow->dwType)); printf("\tStatus: %s\n", get_iface_status(ifRow->dwOperStatus)); (ф-ции get_iface_type & get_iface_status возвращают строчки-описания типа и статуса. Их определения см. в исходниках). 6. Одно из самых интересных возвращаемых полей - MAC-адрес интерфейса. В структуре есть поле, определяющее длину физического адреса. Я (лично я) еще не встречал размер адреса, отличный от 6 байт. Поэтому данное поле проверять не будем. Итак: ![]() ![]() printf("\tAddress: %02x:%02x:%02x:%02x:%02x:%02x\n", ifRow->bPhysAddr[0], ifRow->bPhysAddr[1], ifRow->bPhysAddr[2], ifRow->bPhysAddr[3], ifRow->bPhysAddr[4], ifRow->bPhysAddr[5] ); ...MAC-адрес адаптера как на ладони! Бери и пользуйся. ![]() 7. Многих еще интересует, а сколько данных ушло в сеть, а сколько оттуда пришло. Данные измеряются: а) в пакетах, которые прошли через адаптер; б) в октетах (байтах). Кроме того, пакеты подразделяются на некастовые и юникастовые (любопытные могут обратиться к документации). Отобразим все данные: кол-во байт, некастовые пакеты, юникастовые и общее количество пакетов: ![]() ![]() printf("\tBytes out transfered: %d b (In %d (non-cast) + %d (unicast) = %d packets)\n", ifRow->dwOutOctets, ifRow->dwOutNUcastPkts, ifRow->dwOutUcastPkts, ifRow->dwOutNUcastPkts + ifRow->dwOutUcastPkts); printf("\tBytes in transfered: %d b (In %d (non-cast) + %d (unicast) = %d packets)\n", ifRow->dwInOctets, ifRow->dwInNUcastPkts, ifRow->dwInUcastPkts, ifRow->dwInNUcastPkts + ifRow->dwInUcastPkts); 8. Также многие интересуются скоростью, которую может выдать адаптер. ВНИМАНИЕ: Не путать эту скорость со скоростью канала! Означенная скорость показывает, с какой максимальной скоростью адаптер может пропускать через себя данные! Так что, если вы увидите там 100 МБит/сек, а любимый порнофильм качается со скоростью 5 кБайт/сек, то не надо валить на некорректность данных - тут все правильно и вас никто не обманывает. ![]() ![]() printf("\tInterface speed: %d Bits per seconds\n", ifRow->dwSpeed); 9. А теперь самое интересное! IP-адрес, назначенный данному интерфейсу. Проблема в том, что ф-ция GetIfTable не предоставляет нам такую информацию. Есть другая ф-ция: GetIpAddrTable. Затычка в том, что она работает также, как и GetIfTable. Т.е. возвращает массив структур с данными, в котором нужная информация и хранится. Но там есть поле dwIndex, которое по смыслу совпадает с тем, что нам возвращает в массиве GetIfTable. Чтобы не вызывать при каждой итерации ф-цию GetIpAddrEntry, которая возвращает всего одно поле по заданному индексу, создадим буфер и всю информацию туда затолкаем. Затем при каждой итерации будем искать нужное нам поле и по нему получать информацию по адресам. Этим занимаются 2 функции: get_ifaces_table - получает всю таблицу для всех адаптеров и get_iface_ipaddrow - получает нужную строчку по заданному индексу адаптера. Их исходные тексты см. в исходном тексте. Сперва, перед перечислением адаптеров, получим таблицу с адресами для адаптеров. Для этого изменим немного п.3: ![]() ![]() MIB_IPADDRTABLE * pAddresses = get_ifaces_table(); if ( !pAddresses ) printf("WARNING: Unable to obtain ip addresses table!\n\n"); printf("Total entries: %d\nEnumerating...\n", pTable->dwNumEntries); for(unsigned int i = 0; i < pTable->dwNumEntries; ++i) { Теперь у нас есть сразу и таблица с адресами, к которой будем обращаться в цикле. Вернемся к п.9. В нем будем извлекать с помощью get_iface_ipaddrow поле, соответствующее текущему перечисляемому адаптеру: ![]() ![]() if ( pAddresses ) { MIB_IPADDRROW * pAddr = get_iface_ipaddrow(ifRow->dwIndex, pAddresses); if ( pAddr ) { BYTE * addr = (BYTE*) &pAddr->dwAddr; char str[255]; get_ipaddr_type( str, pAddr->wType ); printf("\tIP address: %d.%d.%d.%d ( %s)\n", addr[0], addr[1], addr[2], addr[3], str); addr = (BYTE*) &pAddr->dwMask; printf("\tNetwork mask: %d.%d.%d.%d\n", addr[0], addr[1], addr[2], addr[3]); } } Здесь мы увидим сам IP-адрес, маску подсети и тип адреса: динамический (напр.: присвоен DHCP), отключенный или предназначенный для удаления (см. полное перечисление типов в MSDN). Тип адреса нам отобразит ф-ция get_ipaddr_type, которая также может быть найдена в исходниках. На сим наш экскурс в мир IpHlpApi закончился. Мы получили много всяких интересных данных, но...!! А как же адреса DNS? А как же то, что у одного адаптера может быть несколько IP-адресов, в конце концов и шлюз должен быть??!!! Впрочем, хочется менять IP-адрес и прочие параметры? Где это все? Но, не все сразу! Дабы не слыть людьми темными и уметь разбираться в предложенном материале, предлагаю для самостоятельного изучения такие ф-ции как: AddIpAddress и DeleteIpAddress. Кучу всего интересного сможете найти также и тут. Итак, прозвенел звонок, лекция окончилась. Вероятно, тема будет продолжена. Если сия информация Вам помогла - буду рад благодарностям в комментариях, если нет - критике туда же. Если благодарностей будет больше - продолжу. ![]() © ALXR. Founder1e2@gmail.com А теперь, обещанный исходный текст: Прикреплённый файл ![]() |
Сообщ.
#2
,
|
|
|
Спасибо большое, очень полезная информация
![]() попробую переписать таким методом, а не через реестр. а вот перезапустить сетевой интерфейс с назначенными параметрами я так понял нет такой функции? |
![]() |
Сообщ.
#3
,
|
|
Цитата boss_ua @ а вот перезапустить сетевой интерфейс с назначенными параметрами я так понял нет такой функции? А зачем? |
Сообщ.
#4
,
|
|
|
ALXR, спасибо, продолжай плз
![]() |
Сообщ.
#5
,
|
|
|
Цитата ALXR @ Цитата boss_ua @ а вот перезапустить сетевой интерфейс с назначенными параметрами я так понял нет такой функции? А зачем? тоесть когда мы меняем настройки то они тут же вступают в силу, так как это проискодит когда я меняю настройки в "Сетевых подключениях"? |
Сообщ.
#6
,
|
|
|
По вопросам №1 и 3 - можно ещё пойти другим путем - с использованием WMI c запросом к Win32_NetworkAdapterConfiguration.
К сожалению, у меня есть исходники только для BCB, оформленные в компонент. Но по "Win32_NetworkAdapterConfiguration" google выдаст код и для VS. Да и в MSDN есть примеры Шлюзы и т.п. можно узнать запросом к Win32_IP4RouteTable |
![]() |
Сообщ.
#7
,
|
|
Ну не знаю... WMI тяжеловат, ИМХО.
|
Сообщ.
#8
,
|
|
|
Цитата ALXR @ Ну не знаю... WMI тяжеловат, ИМХО. если в получении информации скорость не критична то wmi самое то что нужно. |
Сообщ.
#9
,
|
|
|
Цитата если в получении информации скорость не критична то wmi самое то что нужно. WMI - отличный способ собрать инфу о системе, но с его помощью нельзя ничего менять, в данном случае ИП адрес. Так что для п.2 WMI явно не подходит. |
Сообщ.
#10
,
|
|
|
Цитата debugx @ WMI - отличный способ собрать инфу о системе, но с его помощью нельзя ничего менять, в данном случае ИП адрес. Так что для п.2 WMI явно не подходит. опа что то новенькое... Win32_NetworkAdapterConfiguration Class имеет следующие методы ![]() ![]() DisableIPSec EnableDHCP EnableDNS EnableIPFilterSec EnableIPSec EnableStatic //Ставим ип EnableWINS ReleaseDHCPLease ReleaseDHCPLeaseAll RenewDHCPLease RenewDHCPLeaseAll SetArpAlwaysSourceRoute SetArpUseEtherSNAP SetDatabasePath SetDeadGWDetect SetDefaultTOS SetDefaultTTL SetDNSDomain SetDNSServerSearchOrder SetDNSSuffixSearchOrder SetDynamicDNSRegistration SetForwardBufferMemory SetGateways SetIGMPLevel SetIPConnectionMetric SetIPUseZeroBroadcast SetIPXFrameTypeNetworkPairs SetIPXVirtualNetworkNumber SetKeepAliveInterval SetKeepAliveTime SetMTU SetNumForwardPackets SetPMTUBHDetect SetPMTUDiscovery SetTcpipNetbios SetTcpMaxConnectRetransmissions SetTcpMaxDataRetransmissions SetTcpNumConnections SetTcpUseRFC1122UrgentPointer SetTcpWindowSize SetWINSServer |
![]() |
Сообщ.
#11
,
|
|
А можно не создавать холивар на тему WMI vs WinAPI?
|
Сообщ.
#12
,
|
|
|
Цитата ALXR @ Это точно. Ещё и тут - этого не надо. А можно не создавать холивар на тему WMI vs WinAPI? ![]() Просто хотелось отметить, что есть и другие "легальные" способы. На работе у меня затишье (перед бурей) и вчера я начал оформлять код для VC - пусть будет в этом топике? А что лучше - тут и в самом деле - кому что больше по-душе. P.S. До чего неудобно в VC с variant'овским safearray - есть какая нибудь обёртка, ATL-вская например? А то как раз п.2 через VMI на этом завязан (Win32_NetworkAdapterConfiguration::EnableStatic как раз задаёт статический IP и параметрами принимает эти самые VT_SAFEARRAY) Добавлено CComSafeArray - вроде оно, но что-то с типом BSTR как-то не дружит? |
Сообщ.
#13
,
|
|
|
Ещё можно менять IP адрес с помощью недокументированной ф-ции SetAdapterIpAddress.
Ссылки на ее описание и коротенькие примеры я писал здесь : Установить IP,DNS,Gateway программно Однако я слышал, что под вистой она не работает. |
![]() |
Сообщ.
#14
,
|
|
Штука в том, что у адептера может быть с десяток IP-адресов. Короче говоря - список. Задавать можно ф-циями из (см. 1-ый пост).
|
Сообщ.
#15
,
|
|
|
Проблема возникла использую GetIfTable для получения индекса сетевого интерфейса по его имени.
А мне в структуре MIB_IFROW поле wszName функция не инициализирует то есть там пусто(если всю структуру изначально занулить или бред если не занулять) главное все остальное верное. Использую вот этот код: http://msdn.microsoft.com/en-us/library/aa365943(VS.85).aspx |