Состояние локального компьютера
Если нужно узнать состояние портов локального компьютера, нет необходимости сканировать порты. Есть способ лучше — запросить состояние всех портов с помощью функции GetTcpTable. В этом случае вы получите более подробную информацию, которую можно свести в таблицу из следующих колонок:
локальный адрес — интерфейс, на котором открыт порт;
локальный порт — открытый порт;
удаленный адрес — адрес, с которого в данный момент установлено соединение с портом;
удаленный порт — порт на удаленной машине, через который происходит обращение к локальной машине;
состояние — может принимать различные значения: прослушивание, закрытие порта, принятие соединения и т. д.
Самое главное преимущество использования состояния локальной таблицы TCP — мгновенная работа. Сколько бы ни было открытых портов, их определение происходит в считанные миллисекунды.
Для иллюстрации примера работы с TCP-портом создайте MFC-приложение на основе диалогового окна с именем IPState. На главное диалоговое окно поместите один список типа List Box и кнопку с заголовком TCP Table. На 6.3 вы можете увидеть окно будущей программы.

6.3. Окно будущей программы IPState
По нажатии кнопки TCP Table должен выполняться код из листинга 6.3.
| Листинг 6.3. Получение информации о ТСР-портах |
dwStatus = GetTcpTable(pTcpTable, dwActualSize, TRUE);
pTcpTable = (PMIB_TCPTABLE) malloc(dwActualSize); assert(pTcpTable);
dwStatus = GetTcpTable(pTcpTable, dwActualSize, TRUE); if (dwStatus != NO_ERROR) { AfxMessageBox("Couldn't get tcp connection table."); free(pTcpTable); return; }
CString strState; struct in_addr inadLocal, inadRemote; DWORD dwRemotePort = 0; char szLocalIp[1000]; char szRemIp[1000];
if (pTcpTable != NULL) { lList.AddString("================================================="); lList.AddString("TCP table:"); for (int i=0; ipTcpTable-dwNumEntries; i++) { dwRemotePort = 0; switch (pTcpTable-table[i].dwState) { case MIB_TCP_STATE_LISTEN: strState="Listen"; dwRemotePort = pTcpTable-table[i].dwRemotePort; break; case MIB_TCP_STATE_CLOSED: strState="Closed"; break; case MIB_TCP_STATE_TIME_WAIT: strState="Time wait"; break; case MIB_TCP_STATE_LAST_ACK: strState="Last ACK"; break; case MIB_TCP_STATE_CLOSING: strState="Closing"; break; case MIB_TCP_STATE_CLOSE_WAIT: strState="Close Wait"; break; case MIB_TCP_STATE_FIN_WAIT1: strState="FIN wait"; break; case MIB_TCP_STATE_ESTAB: strState="EStab"; break; case MIB_TCP_STATE_SYN_RCVD: strState="SYN Received"; break; case MIB_TCP_STATE_SYN_SENT: strState="SYN Sent"; break; case MIB_TCP_STATE_DELETE_TCB: strState="Delete"; break; } inadLocal.s_addr = pTcpTable-table[i].dwLocalAddr; inadRemote.s_addr = pTcpTable-table[i].dwRemoteAddr; strcpy(szLocalIp, inet_ntoa(inadLocal)); strcpy(szRemIp, inet_ntoa(inadRemote));
char prtStr[1000]; sprintf(prtStr, "Loc Addr %1s; Loc Port %1u; Rem Addr %1s; Rem Port %1u; State %s;", szLocalIp, ntohs((unsigned short) (0x0000FFFF pTcpTable-table[i].dwLocalPort)), szRemIp, ntohs((unsigned short)(0x0000FFFF dwRemotePort)), strState); lList.AddString(prtStr); } } free(pTcpTable); }
У функции GetTcpTable три параметра:
структура типа PMIB_TCPTABLE;
размер структуры, указанной в качестве первого параметра;
признак сортировки — если указано TRUE, то таблица будет отсортирована по номеру порта, иначе данные будут представлены в перемешанном виде.
Если в качестве первых двух параметров указать нулевое значение, то во втором параметре будет получен необходимый размер для хранения структур PMIB_TCPTABLE. Этот прием мы уже не раз использовали в главе 5.
Память определенного размера выделяется функцией malloc. В данном случае это необязательно делать в глобальной области.
Повторный вызов функции GetTcpTable позволяет через первый параметр (переменная рТсрTаblе типа PMIB_TCPTABLE) получить данные о состоянии всех TCP-портов. Их количество находится в параметре dwNumEntries структуры рТсрTаblе. Информацию об определенном порте можно узнать из параметра table[i], где i — номер порта. Этот параметр тоже является структурой, и в нем нас интересуют следующие элементы:
dwState — состояние порта. Этот параметр может принимать различные значения (MIB_TCP_STATE_LISTEN, MIB_TCP_STATE_CLOSED и т. д.). Список всех констант можно найти в коде программы или в справочной системе. Назначение констант просто определить, достаточно только внимательно посмотреть на код из листинга 6.3;
dwLocalPort — локальный порт;
dwRemotePort — удаленный порт;
dwLocalAddr — локальный адрес;
dwRemoteAddr — удаленный адрес.
В примере запускается бесконечный цикл, который перебирает все записи из параметра table, и информация добавляется в список List Box.

6.4. Результат работы программы IPState
Для правильной компиляции программы в начале модуля надо подключить три заголовочных файла:
#include iphlpapi.h
#include assert.h
#include winsock2.h
В свойствах проекта, в разделе Linker/Input в пункте Additional Dependencies нужно добавить две библиотеки IPHlpApi.lib и ws2_32.lib ( 6.5).
Для получения таблицы UDP- портов используется функция GetUdpTable. Она работает аналогично, но узнать можно только локальный адрес и локальный порт, потому что протокол UDP не устанавливает соединения, и нет сведений об удаленном компьютере.
Давайте добавим в программу кнопку UDP Table, а по ее нажатии должен будет выполняться код из листинга 6.4.

6.5. Подключение библиотек
| Листинг 6.4. Получение таблицы состояния UDP-портов |
dwStatus = GetUdpTable(pUdpTable, dwActualSize, TRUE);
pUdpTable = (PMIB_UDPTABLE) malloc(dwActualSize); assert(pUdpTable);
dwStatus = GetUdpTable(pUdpTable, dwActualSize, TRUE);
if (dwStatus != NO_ERROR) { AfxMessageBox("Couldn't get udp connection table."); free(pUdpTable); return; }
struct in_addr inadLocal; if (pUdpTable != NULL) { lList.AddString("================================================="); lList.AddString("UDP table:"); for (UINT i = 0; i pUdpTable-dwNumEntries; ++i) { inadLocal.s_addr = pUdpTable-table[i].dwLocalAddr;
char prtStr[1000]; sprintf(prtStr, "Loc Addr %1s; Loc Port %1u", inet_ntoa(inadLocal), ntohs((unsigned short)(0x0000FFFF pUdpTable-table[i].dwLocalPort))); lList.AddString(prtStr); } } free(pUdpTable); }
Код для получения информации о UDP похож на тот, что использовался для протокола TCP, и вам не составит труда разобраться с происходящим.
| Примечание |
| Исходный код примера, описанного в этом разделе, вы можете найти на компакт - диске в каталоге \Demo\Chapter6\IPState. |
![]() |
![]() |

