You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过C++ WinAPI获取本地TCP客户端连接的进程名称

获取本地TCP连接发起进程名称的WinAPI实现方法

要在Windows下通过C++ WinAPI获取本地TCP客户端连接的发起进程名称,可按以下步骤实现:

核心逻辑

  1. 从已接受的客户端套接字中提取本地IP/端口和远程IP/端口四元组信息
  2. 查询系统TCP连接表,匹配四元组得到对应进程ID(PID)
  3. 通过PID打开进程,读取进程可执行文件路径并提取名称

依赖头文件与库

除原有WinSock相关头文件外,还需添加:

#include <iphlpapi.h>
#include <psapi.h>
#include <shlwapi.h>

#pragma comment(lib, "Iphlpapi.lib")
#pragma comment(lib, "Psapi.lib")
#pragma comment(lib, "Shlwapi.lib")

修改后的完整服务器代码

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <string>
#include <iphlpapi.h>
#include <psapi.h>
#include <shlwapi.h>

#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Iphlpapi.lib")
#pragma comment(lib, "Psapi.lib")
#pragma comment(lib, "Shlwapi.lib")

// 根据套接字获取连接进程名称
std::string GetClientProcessName(SOCKET clientSocket) {
    // 获取本地地址和远程地址
    sockaddr_in localAddr{}, remoteAddr{};
    int addrLen = sizeof(localAddr);
    if (getsockname(clientSocket, (sockaddr*)&localAddr, &addrLen) == SOCKET_ERROR) {
        return "Failed to get local address";
    }
    addrLen = sizeof(remoteAddr);
    if (getpeername(clientSocket, (sockaddr*)&remoteAddr, &addrLen) == SOCKET_ERROR) {
        return "Failed to get remote address";
    }

    // 查询TCP连接表
    DWORD tableSize = 0;
    GetExtendedTcpTable(nullptr, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
    auto tcpTable = (PMIB_TCPTABLE_OWNER_PID)malloc(tableSize);
    if (!tcpTable) {
        return "Failed to allocate memory for TCP table";
    }

    if (GetExtendedTcpTable(tcpTable, &tableSize, FALSE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0) != NO_ERROR) {
        free(tcpTable);
        return "Failed to get TCP table";
    }

    // 遍历连接表匹配四元组
    DWORD clientPID = 0;
    for (DWORD i = 0; i < tcpTable->dwNumEntries; ++i) {
        auto& entry = tcpTable->table[i];
        // 匹配本地端口、远程端口、本地IP、远程IP
        if (entry.dwLocalPort == ntohs(localAddr.sin_port) &&
            entry.dwRemotePort == ntohs(remoteAddr.sin_port) &&
            entry.dwLocalAddr == localAddr.sin_addr.s_addr &&
            entry.dwRemoteAddr == remoteAddr.sin_addr.s_addr &&
            entry.dwState == MIB_TCP_STATE_ESTABLISHED) {
            clientPID = entry.dwOwningPid;
            break;
        }
    }
    free(tcpTable);

    if (clientPID == 0) {
        return "No matching process found";
    }

    // 通过PID获取进程名称
    HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, clientPID);
    if (!hProcess) {
        return "Failed to open process";
    }

    char processPath[MAX_PATH] = {0};
    GetModuleFileNameExA(hProcess, nullptr, processPath, MAX_PATH);
    CloseHandle(hProcess);

    // 提取文件名(进程名称)
    return PathFindFileNameA(processPath);
}

int main() {
    WSADATA wsaData;
    SOCKET listenSocket = INVALID_SOCKET;
    SOCKET clientSocket = INVALID_SOCKET;
    sockaddr_in serverAddr;

    // 初始化WinSock
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        std::cerr << "WSAStartup失败: " << WSAGetLastError() << std::endl;
        return 1;
    }

    // 创建套接字
    listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (listenSocket == INVALID_SOCKET) {
        std::cerr << "套接字创建失败: " << WSAGetLastError() << std::endl;
        WSACleanup();
        return 1;
    }

    // 设置服务器地址
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(8282);

    // 绑定套接字
    if (bind(listenSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
        std::cerr << "绑定失败: " << WSAGetLastError() << std::endl;
        closesocket(listenSocket);
        WSACleanup();
        return 1;
    }

    // 监听连接
    if (listen(listenSocket, SOMAXCONN) == SOCKET_ERROR) {
        std::cerr << "监听失败: " << WSAGetLastError() << std::endl;
        closesocket(listenSocket);
        WSACleanup();
        return 1;
    }

    std::cout << "等待端口8282上的连接..." << std::endl;

    // 接受连接
    clientSocket = accept(listenSocket, nullptr, nullptr);
    if (clientSocket == INVALID_SOCKET) {
        std::cerr << "接受连接失败: " << WSAGetLastError() << std::endl;
        closesocket(listenSocket);
        WSACleanup();
        return 1;
    }

    // 获取客户端进程名称
    std::string processName = GetClientProcessName(clientSocket);
    std::cout << "客户端进程名称: " << processName << std::endl;

    // 接收请求
    char buffer[1024] = { 0 };
    recv(clientSocket, buffer, sizeof(buffer) - 1, 0);
    std::cout << "收到请求:\n" << buffer << std::endl;

    // 发送响应
    const char* response = "data";
    send(clientSocket, response, strlen(response), 0);
    std::cout << "响应已发送。" << std::endl;

    // 清理资源
    closesocket(clientSocket);
    closesocket(listenSocket);
    WSACleanup();

    return 0;
}

关键说明

  • TCP连接表查询:使用GetExtendedTcpTable获取包含PID的TCP连接信息,需先调用一次获取所需内存大小,再分配内存查询
  • 进程权限:OpenProcess需要PROCESS_QUERY_INFORMATION和PROCESS_VM_READ权限,若目标进程是系统进程或高权限进程,当前程序需以管理员权限运行
  • 兼容性:代码适配IPv4,若需支持IPv6,需修改为AF_INET6并使用对应MIB结构体

内容的提问来源于stack exchange,提问作者Joe J

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 06:09:51