文章目录
GetExtendedTcpTable
https://docs.microsoft.com/zh-cn/windows/win32/api/iphlpapi/nf-iphlpapi-getextendedtcptable
相当于执行
netstat -at
IPHLPAPI_DLL_LINKAGE DWORD GetExtendedTcpTable(
[out] PVOID pTcpTable,
[in, out] PDWORD pdwSize,
[in] BOOL bOrder,
[in] ULONG ulAf,
[in] TCP_TABLE_CLASS TableClass,
[in] ULONG Reserved
);
参数①PVOID pTcpTable
指向查询结果结构体的指针,可以根据参数⑤设置不同的结构体
MIB_TCPTABLE
https://docs.microsoft.com/en-us/windows/win32/api/tcpmib/ns-tcpmib-mib_tcptable
typedef struct _MIB_TCPTABLE {
DWORD dwNumEntries;
MIB_TCPROW table[ANY_SIZE];
} MIB_TCPTABLE, *PMIB_TCPTABLE;
成员①为数组元素个数
成员②为MIB_TCPROW结构体数组,结构体定义如下
typedef struct _MIB_TCPROW_LH {
union {
DWORD dwState;
MIB_TCP_STATE State;
};//TCP通信状态,例如:CLOSED,LISTEN,SYN_SENT等
DWORD dwLocalAddr;
DWORD dwLocalPort;
DWORD dwRemoteAddr;
DWORD dwRemotePort;
} MIB_TCPROW_LH, *PMIB_TCPROW_LH;
实例代码中用的是MIB_TCPTABLE_OWNER_MODULE,因为后面还需要获取每个通信进程对应的应用程序:
https://docs.microsoft.com/en-us/windows/win32/api/tcpmib/ns-tcpmib-mib_tcptable_owner_module
typedef struct _MIB_TCPTABLE_OWNER_MODULE {
DWORD dwNumEntries;
MIB_TCPROW_OWNER_MODULE table[ANY_SIZE];
} MIB_TCPTABLE_OWNER_MODULE, *PMIB_TCPTABLE_OWNER_MODULE;
成员①为数组元素个数
成员②为MIB_TCPROW_OWNER_MODULE结构体数组,结构体定义如下:
https://docs.microsoft.com/en-us/windows/win32/api/tcpmib/ns-tcpmib-mib_tcprow_owner_module
typedef struct _MIB_TCPROW_OWNER_MODULE {
DWORD dwState;//TCP通信状态,例如:CLOSED,LISTEN,SYN_SENT等
DWORD dwLocalAddr;//本地IP地址
DWORD dwLocalPort;//本地端口
DWORD dwRemoteAddr;//远程IP地址
DWORD dwRemotePort;//远程端口
DWORD dwOwningPid;//进程号
LARGE_INTEGER liCreateTimestamp;//创建连接的时间戳
ULONGLONG OwningModuleInfo[TCPIP_OWNING_MODULE_SIZE];//进程模块信息
} MIB_TCPROW_OWNER_MODULE, *PMIB_TCPROW_OWNER_MODULE;
参数②PDWORD pdwSize
返回参数①的大小
参数③BOOL bOrder
是否升序排序,按以下信息进行排序:
1.本地IP地址
2.IPv6的本地域ID
3.本地端口号
4.远程IP地址
5.IPv6的远程域ID
6.远程端口号
参数④ULONG ulAf
IP地址簇类型,AF_INET对应IPv4,AF_INET6对应IPv6
参数⑤TCP_TABLE_CLASS TableClass
参数①类型,这里设置为TCP_TABLE_OWNER_MODULE_ALL
https://docs.microsoft.com/en-us/windows/win32/api/iprtrmib/ne-iprtrmib-tcp_table_class
typedef enum _TCP_TABLE_CLASS {
TCP_TABLE_BASIC_LISTENER,
TCP_TABLE_BASIC_CONNECTIONS,
TCP_TABLE_BASIC_ALL,
TCP_TABLE_OWNER_PID_LISTENER,
TCP_TABLE_OWNER_PID_CONNECTIONS,
TCP_TABLE_OWNER_PID_ALL,
TCP_TABLE_OWNER_MODULE_LISTENER,
TCP_TABLE_OWNER_MODULE_CONNECTIONS,
TCP_TABLE_OWNER_MODULE_ALL
} TCP_TABLE_CLASS, *PTCP_TABLE_CLASS;
从上面结构体成员名称带有不同关键字,具有不同含义,对于IPv4协议:
名称 | 含义 |
---|---|
LISTENER | 仅含接收端为listening状态的通信信息 |
CONNECTIONS | 仅含终端为connected状态的通信信息 |
ALL | 包含所有的通信信息 |
BASIC | 包含基本的通信信息,通信状态、本地地址与端口,远程地址与端口,参数①对应结构体为MIB_TCPTABLE |
OWNER_PID | 除基本信息外还包含进程号,参数①对应结构体为MIB_TCPTABLE_OWNER_PID |
OWNER_MODULE | 除基本信息外还包含进程号与创建时间,参数①对应结构体为MIB_TCPTABLE_OWNER_MODULE |
参数⑥ULONG Reserved
保留参数。
返回值
成功:NO_ERROR
失败:错误码,其中ERROR_INSUFFICIENT_BUFFER表示分配的内存不足,需要重新获取
实例代码
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <iphlpapi.h>//这个头文件位置不能和winsock2.h互换
#include <stdio.h>
#include<TCHAR.h>
#pragma comment(lib, "IPHLPAPI.lib")
#pragma comment(lib,"ws2_32.lib")
char Buf[0x1000];
int main()
{
WORD wVersionRequested = MAKEWORD(2, 2);//版本
WSADATA wsaDATA;
if (WSAStartup(wVersionRequested, &wsaDATA) != 0)//打开网络库
{
printf("打开网络库失败!\n");
return -1;
}
PMIB_TCPTABLE_OWNER_MODULE pInfo = NULL;
ULONG Length = 0;
DWORD re = GetExtendedTcpTable(pInfo, &Length, TRUE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL,0);//第一次调用获取长度
if (ERROR_INSUFFICIENT_BUFFER == re)//根据长度申请内存
{
pInfo = (PMIB_TCPTABLE_OWNER_MODULE)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, Length);
}
re = GetExtendedTcpTable(pInfo, &Length, TRUE, AF_INET, TCP_TABLE_OWNER_MODULE_ALL,0); //第二次调用获取信息
if (NO_ERROR != re)
{
printf("获取TCP通信信息失败,错误码为:%d\n", re);
HeapFree(GetProcessHeap(), 0, (pInfo));
return -1;
}
for (DWORD i = 0; i < pInfo->dwNumEntries; i++)
{
PTCPIP_OWNER_MODULE_BASIC_INFO pInfo_app = (PTCPIP_OWNER_MODULE_BASIC_INFO)Buf;
DWORD Length = 0x1000;
re = GetOwnerModuleFromTcpEntry(&pInfo->table[i], TCPIP_OWNER_MODULE_INFO_BASIC, pInfo_app, &Length);//获取通信对应的应用程序信息
_tprintf(L"%d. %s\n\t%s\n", i, pInfo_app->pModulePath, pInfo_app->pModuleName);//输出序号、程序路径、程序名称
in_addr Local, Remote;
Local.S_un.S_addr = pInfo->table[i].dwLocalAddr;
Remote.S_un.S_addr = pInfo->table[i].dwRemoteAddr;
printf("\t%s:%d\t", inet_ntoa(Local), ntohs(pInfo->table[i].dwLocalPort)); //输出本地IP和端口
printf("\n\t%s:%d\n", inet_ntoa(Remote), ntohs(pInfo->table[i].dwRemotePort));//输出远程IP和端口
switch (pInfo->table[i].dwState) //根据状态码打印对应状态
{
case MIB_TCP_STATE_CLOSED:
printf("\tCLOSED\n");
break;
case MIB_TCP_STATE_LISTEN:
printf("\tLISTEN\n");
break;
case MIB_TCP_STATE_SYN_SENT:
printf("\tSYN-SENT\n");
break;
case MIB_TCP_STATE_SYN_RCVD:
printf("\tSYN-RECEIVED\n");
break;
case MIB_TCP_STATE_ESTAB:
printf("\tESTABLISHED\n");
break;
case MIB_TCP_STATE_FIN_WAIT1:
printf("\tFIN-WAIT-1\n");
break;
case MIB_TCP_STATE_FIN_WAIT2:
printf("\tFIN-WAIT-2 \n");
break;
case MIB_TCP_STATE_CLOSE_WAIT:
printf("\tCLOSE-WAIT\n");
break;
case MIB_TCP_STATE_CLOSING:
printf("\tCLOSING\n");
break;
case MIB_TCP_STATE_LAST_ACK:
printf("\tLAST-ACK\n");
break;
case MIB_TCP_STATE_TIME_WAIT:
printf("\tTIME-WAIT\n");
break;
case MIB_TCP_STATE_DELETE_TCB:
printf("\tDELETE-TCB\n");
break;
default:
printf("\tUNKNOWN dwState value: %d\n", pInfo->table[i].dwState);
break;
}
}
if (pInfo != NULL) {
HeapFree(GetProcessHeap(), 0, (pInfo));
pInfo = NULL;
}
WSACleanup();
getchar();
return 0;
}
运行结果如下图:
除了TCP外,还有对应获取UDP通信信息的函数,相当于执行netstat -au
https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getextendedudptable
IPHLPAPI_DLL_LINKAGE DWORD GetExtendedUdpTable(
[out] PVOID pUdpTable,
[in, out] PDWORD pdwSize,
[in] BOOL bOrder,
[in] ULONG ulAf,
[in] UDP_TABLE_CLASS TableClass,
[in] ULONG Reserved
);
使用方法与GetExtendedTcpTable一样,仅在参数的取值上有一些不一样,这里不再赘述。
注意:这里涉及到的结构体一层套一层,初学者很难进行分辨,记忆要点在于将通信信息最后看做一张表格:
函数GetExtendedTcpTable获取的就是这个表格(Table)大结构体,表格是由多行(Row)组成,把每一行看做一个元素,那么表格就相当于由行数组组成,表格中每一行Row也就是小结构体每个对应一条TCP通信信息(本地IP和端口、远程IP和端口、状态等。)
GetOwnerModuleFromTcpEntry
https://docs.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getownermodulefromtcpentry
IPHLPAPI_DLL_LINKAGE DWORD GetOwnerModuleFromTcpEntry(
[in] PMIB_TCPROW_OWNER_MODULE pTcpEntry,
[in] TCPIP_OWNER_MODULE_INFO_CLASS Class,
[out] PVOID pBuffer,
[in, out] PDWORD pdwSize
);
参数①
就是表格中的行数组元素
MIB_TCPROW_OWNER_MODULE结构体数组,结构体定义如下:
https://docs.microsoft.com/en-us/windows/win32/api/tcpmib/ns-tcpmib-mib_tcprow_owner_module
typedef struct _MIB_TCPROW_OWNER_MODULE {
DWORD dwState;//TCP通信状态,例如:CLOSED,LISTEN,SYN_SENT等
DWORD dwLocalAddr;//本地IP地址
DWORD dwLocalPort;//本地端口
DWORD dwRemoteAddr;//远程IP地址
DWORD dwRemotePort;//远程端口
DWORD dwOwningPid;//进程号
LARGE_INTEGER liCreateTimestamp;//创建连接的时间戳
ULONGLONG OwningModuleInfo[TCPIP_OWNING_MODULE_SIZE];//进程模块信息
} MIB_TCPROW_OWNER_MODULE, *PMIB_TCPROW_OWNER_MODULE;
参数②
TCPIP_OWNER_MODULE_INFO_CLASS枚举类型
参数③
TCPIP_OWNER_MODULE_BASIC_INFO结构体
https://docs.microsoft.com/en-us/windows/win32/api/iprtrmib/ns-iprtrmib-tcpip_owner_module_basic_info
typedef struct _TCPIP_OWNER_MODULE_BASIC_INFO {
PWCHAR pModuleName;
PWCHAR pModulePath;
} TCPIP_OWNER_MODULE_BASIC_INFO, *PTCPIP_OWNER_MODULE_BASIC_INFO;
传址调用,因此这里两个成员都必须为NULL
成员①:应用程序路径+名称
成员②:应用程序名称
由于应用程序路径里面包含特殊符号,输出的时候用_tprintf。
参数④
参数③的大小
返回值
成功:NO_ERROR
失败:错误码,ERROR_INSUFFICIENT_BUFFER为参数①大小不足的错误,需要重新申请内存。