개발/WIN32-MFC

[ WIN ] Get PID From Socket ID

-=HaeJuK=- 2024. 8. 1. 15:41


Windows API를 사용하여 특정 소켓에 대한 소켓 ID(SOCKET 또는 소켓 핸들)에서 해당 프로세스 ID(PID)를 찾는 방법에 대해 설명하겠습니다.

Windows에서는 일반적으로 SOCKET 핸들과 직접적으로 관련된 API가 없기 때문에 소켓 ID에서 PID를 얻기 위해 네트워크 연결 테이블을 탐색해야 합니다.

GetExtendedTcpTable 및 GetExtendedUdpTable 함수를 사용하여 시스템의 모든 TCP/UDP 연결을 조회하고, 해당 테이블에서 일치하는 소켓 핸들을 찾아서 그에 대응하는 PID를 얻을 수 있습니다.

아래는 C++로 작성된 예제로, 주어진 SOCKET 핸들에서 PID를 찾는 방법을 보여줍니다.
이 예제에서는 TCP 연결을 대상으로 합니다.

#include <winsock2.h>
#include <iphlpapi.h>
#include <iostream>
#include <vector>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "iphlpapi.lib")	
typedef unsigned int UInt32;

DWORD GetPidFromSocket(SOCKET _nSocketID)
{
    DWORD dwRetVal = 0;
    DWORD dwSize = 0;

    WSADATA wsaData;
    int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (result != NO_ERROR)
    {
        std::cerr << "WSAStartup failed with error: " << result << std::endl;
        return 0;
    }

    PMIB_TCPTABLE_OWNER_PID pTcpTable = NULL;
    std::vector<char> buffer;

    // First call to GetExtendedTcpTable to determine the size needed
    dwRetVal = GetExtendedTcpTable(NULL, &dwSize, FALSE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
    if (dwRetVal != ERROR_INSUFFICIENT_BUFFER)
    {
        std::cerr << "GetExtendedTcpTable failed to retrieve size with error: " << dwRetVal << std::endl;
        goto Exit;
    }

    buffer.resize(dwSize);
    pTcpTable = reinterpret_cast<PMIB_TCPTABLE_OWNER_PID>(buffer.data());

    // Second call to GetExtendedTcpTable to retrieve the actual data
    dwRetVal = GetExtendedTcpTable(pTcpTable, &dwSize, FALSE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
    if (dwRetVal == NO_ERROR)
    {
        sockaddr_in localAddr;
        int localAddrLen = sizeof(localAddr);
        if (getsockname(_nSocketID, (sockaddr*)&localAddr, &localAddrLen) == 0)
        {
            for (DWORD i = 0; i < pTcpTable->dwNumEntries; i++)
            {
                MIB_TCPROW_OWNER_PID& row = pTcpTable->table[i];
                if (row.dwLocalAddr == localAddr.sin_addr.s_addr &&
                    row.dwLocalPort == ntohs(localAddr.sin_port))
                {
                    dwRetVal = row.dwOwningPid;
                    goto Exit;
                }
            }
        }
        else
        {
            std::cerr << "getsockname failed with error: " << WSAGetLastError() << std::endl;
        }
    }
    else
    {
        std::cerr << "GetExtendedTcpTable failed with " << dwRetVal << std::endl;
    }

Exit:
    WSACleanup();
    return dwRetVal;
}

 

반응형