How to know which Local Application Connected to my socket (Windows)

I have a windows services that bind to some TCP port, this port is use for IPC between my application.

Is there a programming (WinAPI/WinSocket and etc) way to know which application connected to my port?

i.e. in my Windows Services I would like to get a PID of the process that connected to my port.

Yes, you can determine the PID of the process that connected to your TCP port using the Windows IP Helper API, specifically the GetExtendedTcpTable function.

However, Windows does not provide a direct WinSock API call during the connection accept phase (e.g., in accept() or WSAAccept()) to obtain the PID of the remote process. Instead, you can correlate connection data (local/remote IP and port) with the process list using GetExtendedTcpTable.

Option 1: Use GetExtendedTcpTable (from iphlpapi.dll)

Here’s a high-level summary:

  1. Call accept() on your socket and get the SOCKET.
  2. Use getpeername() to get the remote IP and port.
  3. Use getsockname() to confirm the local port.
  4. Call GetExtendedTcpTable() with TCP_TABLE_OWNER_PID_CONNECTIONS.
  5. Iterate over all entries, find the one matching your local/remote tuple.
  6. The matched entry includes the owning PID of the connecting process.

Example (C++)

#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <windows.h>

#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")

DWORD GetRemotePid(SOCKADDR_IN localAddr, SOCKADDR_IN remoteAddr)
{
    PMIB_TCPTABLE_OWNER_PID pTcpTable;
    DWORD dwSize = 0;
    DWORD dwRetVal = 0;

    pTcpTable = (PMIB_TCPTABLE_OWNER_PID) malloc(sizeof(MIB_TCPTABLE_OWNER_PID));
    if (pTcpTable == NULL) return 0;

    dwSize = sizeof(MIB_TCPTABLE_OWNER_PID);
    if ((dwRetVal = GetExtendedTcpTable(pTcpTable, &dwSize, FALSE,
        AF_INET, TCP_TABLE_OWNER_PID_ALL, 0)) == ERROR_INSUFFICIENT_BUFFER)
    {
        free(pTcpTable);
        pTcpTable = (PMIB_TCPTABLE_OWNER_PID) malloc(dwSize);
        if (pTcpTable == NULL) return 0;
    }

    if ((dwRetVal = GetExtendedTcpTable(pTcpTable, &dwSize, FALSE,
        AF_INET, TCP_TABLE_OWNER_PID_ALL, 0)) == NO_ERROR)
    {
        for (DWORD i = 0; i < pTcpTable->dwNumEntries; i++)
        {
            MIB_TCPROW_OWNER_PID row = pTcpTable->table[i];

            if (row.dwLocalPort == ntohs(localAddr.sin_port) &&
                row.dwRemotePort == ntohs(remoteAddr.sin_port) &&
                row.dwRemoteAddr == remoteAddr.sin_addr.S_un.S_addr &&
                row.dwLocalAddr == localAddr.sin_addr.S_un.S_addr)
            {
                DWORD pid = row.dwOwningPid;
                free(pTcpTable);
                return pid;
            }
        }
    }

    free(pTcpTable);
    return 0;
}

Notes

  • Not real-time: There’s a slight delay between connection and when it shows up in GetExtendedTcpTable.
  • Race conditions: In high-load systems, the connection may close before it’s seen.
  • Admin rights: May be required to get owner PIDs of other users’ connections.
  • Does not work cross-machine: This only works for local connections.

Alternative: Use WSAAccept with a conditional function (Still doesn’t give PID)

You can use WSAAccept() with a conditional accept callback to get the connecting client’s address, but still not the PID.

If You Control the Client

If you own both ends of the connection, the best option is to:

  • On the client side, send the PID (e.g., via GetCurrentProcessId()).
  • On the server side, trust it if it runs in a secure environment (e.g., only local trusted apps).

This avoids needing to reverse-engineer the connection-PID mapping.