获取本地TCP通信信息

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为参数①大小不足的错误,需要重新申请内存。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oldmao_2000

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值