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

如何根据端口号或IP地址获取对应进程名称?(基于C#与SharpPcap库场景)

嘿,针对你提出的两个技术诉求,我来给你详细拆解下实现方法:

一、根据端口号获取进程名称

首先得区分操作系统场景,考虑到你用C#开发,大概率是在Windows环境下,我重点讲Windows的实现,也补充下跨平台的思路:

Windows平台实现

方法1:使用WMI查询(代码简单易上手)

WMI(Windows Management Instrumentation)可以直接关联端口和进程,优点是代码量小,缺点是查询速度稍慢,适合低频查询场景。示例代码:

using System.Management;

public static string GetProcessNameByPort(int port)
{
    try
    {
        // 查询TCP连接对应的进程
        var tcpQuery = new ManagementObjectSearcher($"SELECT OwningProcess FROM Win32_TcpConnection WHERE LocalPort = {port}");
        foreach (var obj in tcpQuery.Get())
        {
            uint pid = (uint)obj["OwningProcess"];
            var process = System.Diagnostics.Process.GetProcessById((int)pid);
            return process.ProcessName;
        }
        // 查询UDP端点对应的进程
        var udpQuery = new ManagementObjectSearcher($"SELECT OwningProcess FROM Win32_UdpEndpoint WHERE LocalPort = {port}");
        foreach (var obj in udpQuery.Get())
        {
            uint pid = (uint)obj["OwningProcess"];
            var process = System.Diagnostics.Process.GetProcessById((int)pid);
            return process.ProcessName;
        }
        return "未找到对应进程";
    }
    catch (Exception ex)
    {
        return $"查询失败:{ex.Message}";
    }
}

方法2:调用Windows API(高效推荐)

通过GetExtendedTcpTable和GetExtendedUdpTable直接读取系统内核级的端口-PID映射,速度更快,适合高频查询或实时场景。需要先定义P/Invoke结构和方法,示例代码:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Runtime.InteropServices;

public static class PortProcessMapper
{
    // TCP表结构定义
    [StructLayout(LayoutKind.Sequential)]
    private struct MIB_TCPTABLE_OWNER_PID
    {
        public uint dwNumEntries;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
        public MIB_TCPROW_OWNER_PID[] table;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct MIB_TCPROW_OWNER_PID
    {
        public uint dwState;
        public uint dwLocalAddr;
        public uint dwLocalPort;
        public uint dwRemoteAddr;
        public uint dwRemotePort;
        public uint dwOwningPid;
    }

    // UDP表结构定义
    [StructLayout(LayoutKind.Sequential)]
    private struct MIB_UDPTABLE_OWNER_PID
    {
        public uint dwNumEntries;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
        public MIB_UDPROW_OWNER_PID[] table;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct MIB_UDPROW_OWNER_PID
    {
        public uint dwLocalAddr;
        public uint dwLocalPort;
        public uint dwOwningPid;
    }

    // P/Invoke方法声明
    [DllImport("iphlpapi.dll", SetLastError = true)]
    private static extern uint GetExtendedTcpTable(IntPtr pTcpTable, ref uint pdwSize, bool bOrder, uint ulAf, uint tableClass, uint reserved);

    [DllImport("iphlpapi.dll", SetLastError = true)]
    private static extern uint GetExtendedUdpTable(IntPtr pUdpTable, ref uint pdwSize, bool bOrder, uint ulAf, uint tableClass, uint reserved);

    private const uint AF_INET = 2;
    private const uint TCP_TABLE_OWNER_PID_ALL = 5;
    private const uint UDP_TABLE_OWNER_PID = 1;

    // 获取所有TCP端口-PID映射
    public static Dictionary<(IPAddress, int), int> GetTcpPortPidMap()
    {
        var map = new Dictionary<(IPAddress, int), int>();
        uint size = 0;
        GetExtendedTcpTable(IntPtr.Zero, ref size, false, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
        IntPtr tablePtr = Marshal.AllocHGlobal((int)size);
        try
        {
            if (GetExtendedTcpTable(tablePtr, ref size, false, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0) == 0)
            {
                var table = (MIB_TCPTABLE_OWNER_PID)Marshal.PtrToStructure(tablePtr, typeof(MIB_TCPTABLE_OWNER_PID));
                var rows = new MIB_TCPROW_OWNER_PID[table.dwNumEntries];
                IntPtr rowPtr = (IntPtr)((long)tablePtr + Marshal.SizeOf(table.dwNumEntries));
                for (int i = 0; i < table.dwNumEntries; i++)
                {
                    rows[i] = (MIB_TCPROW_OWNER_PID)Marshal.PtrToStructure(rowPtr, typeof(MIB_TCPROW_OWNER_PID));
                    rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(typeof(MIB_TCPROW_OWNER_PID)));
                    IPAddress localAddr = IPAddress.Parse($"{(rows[i].dwLocalAddr >> 0) & 0xFF}.{(rows[i].dwLocalAddr >> 8) & 0xFF}.{(rows[i].dwLocalAddr >> 16) & 0xFF}.{(rows[i].dwLocalAddr >> 24) & 0xFF}");
                    int localPort = (int)((rows[i].dwLocalPort >> 8) | ((rows[i].dwLocalPort & 0xFF) << 8));
                    map.Add((localAddr, localPort), (int)rows[i].dwOwningPid);
                }
            }
        }
        finally
        {
            Marshal.FreeHGlobal(tablePtr);
        }
        return map;
    }

    // 获取所有UDP端口-PID映射
    public static Dictionary<(IPAddress, int), int> GetUdpPortPidMap()
    {
        var map = new Dictionary<(IPAddress, int), int>();
        uint size = 0;
        GetExtendedUdpTable(IntPtr.Zero, ref size, false, AF_INET, UDP_TABLE_OWNER_PID, 0);
        IntPtr tablePtr = Marshal.AllocHGlobal((int)size);
        try
        {
            if (GetExtendedUdpTable(tablePtr, ref size, false, AF_INET, UDP_TABLE_OWNER_PID, 0) == 0)
            {
                var table = (MIB_UDPTABLE_OWNER_PID)Marshal.PtrToStructure(tablePtr, typeof(MIB_UDPTABLE_OWNER_PID));
                var rows = new MIB_UDPROW_OWNER_PID[table.dwNumEntries];
                IntPtr rowPtr = (IntPtr)((long)tablePtr + Marshal.SizeOf(table.dwNumEntries));
                for (int i = 0; i < table.dwNumEntries; i++)
                {
                    rows[i] = (MIB_UDPROW_OWNER_PID)Marshal.PtrToStructure(rowPtr, typeof(MIB_UDPROW_OWNER_PID));
                    rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(typeof(MIB_UDPROW_OWNER_PID)));
                    IPAddress localAddr = IPAddress.Parse($"{(rows[i].dwLocalAddr >> 0) & 0xFF}.{(rows[i].dwLocalAddr >> 8) & 0xFF}.{(rows[i].dwLocalAddr >> 16) & 0xFF}.{(rows[i].dwLocalAddr >> 24) & 0xFF}");
                    int localPort = (int)((rows[i].dwLocalPort >> 8) | ((rows[i].dwLocalPort & 0xFF) << 8));
                    map.Add((localAddr, localPort), (int)rows[i].dwOwningPid);
                }
            }
        }
        finally
        {
            Marshal.FreeHGlobal(tablePtr);
        }
        return map;
    }

    // 根据IP和端口获取进程名称
    public static string GetProcessNameByIpPort(IPAddress ip, int port, bool isTcp)
    {
        var map = isTcp ? GetTcpPortPidMap() : GetUdpPortPidMap();
        if (map.TryGetValue((ip, port), out int pid))
        {
            try
            {
                var process = Process.GetProcessById(pid);
                return process.ProcessName;
            }
            catch (Exception)
            {
                return $"PID {pid} 对应的进程已退出";
            }
        }
        return "未找到对应进程";
    }
}

跨平台思路(Linux/macOS)

如果你的C#程序需要跨平台运行,可以通过调用系统命令并解析输出的方式实现:

  • Linux:执行ss -tulpn命令,提取端口与PID的映射关系
  • macOS:执行lsof -i :<port>命令,解析结果获取进程信息

以Linux为例,示例代码如下:

public static string GetProcessNameByPortLinux(int port)
{
    var process = new Process
    {
        StartInfo = new ProcessStartInfo
        {
            FileName = "ss",
            Arguments = $"-tulpn | grep :{port}",
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = true
        }
    };
    process.Start();
    string output = process.StandardOutput.ReadToEnd();
    process.WaitForExit();
    if (!string.IsNullOrEmpty(output))
    {
        var pidMatch = System.Text.RegularExpressions.Regex.Match(output, @"pid=(\d+)");
        if (pidMatch.Success && int.TryParse(pidMatch.Groups[1].Value, out int pid))
        {
            return Process.GetProcessById(pid).ProcessName;
        }
    }
    return "未找到对应进程";
}
二、结合SharpPcap获取TCP/UDP连接对应的进程名称

你已经通过SharpPcap拿到了连接信息,接下来只需要把捕获到的数据包中的IP、端口信息和上面的端口-PID映射关联起来即可,具体步骤如下:

  1. 定时刷新系统的端口-PID映射(因为网络连接是动态变化的)
  2. 在SharpPcap的数据包回调中,解析出TCP/UDP的源/目的IP和端口
  3. 根据连接类型,在映射表中查找对应的PID,再获取进程名称

示例代码:

using SharpPcap;
using PacketDotNet;
using System;
using System.Collections.Generic;
using System.Net;

class Program
{
    private static Dictionary<(IPAddress, int), int> _tcpMap;
    private static Dictionary<(IPAddress, int), int> _udpMap;

    static void Main(string[] args)
    {
        // 初始化端口映射,定时每5秒刷新一次
        RefreshPortMaps();
        var timer = new System.Timers.Timer(5000);
        timer.Elapsed += (sender, e) => RefreshPortMaps();
        timer.Start();

        // 获取本地网络设备
        var devices = CaptureDeviceList.Instance;
        if (devices.Count == 0)
        {
            Console.WriteLine("未找到可用的网络设备");
            return;
        }

        // 选择第一个设备开始捕获数据包
        using var device = devices[0];
        device.OnPacketArrival += Device_OnPacketArrival;
        device.Open(DeviceMode.Promiscuous, 1000);
        Console.WriteLine($"开始捕获设备 {device.Name} 的数据包...");
        device.StartCapture();

        Console.WriteLine("按任意键停止捕获");
        Console.ReadKey();
        device.StopCapture();
    }

    private static void RefreshPortMaps()
    {
        _tcpMap = PortProcessMapper.GetTcpPortPidMap();
        _udpMap = PortProcessMapper.GetUdpPortPidMap();
        Console.WriteLine("端口-PID映射已刷新");
    }

    private static void Device_OnPacketArrival(object sender, PacketCapture e)
    {
        var packet = Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);
        var ipPacket = packet.Extract<IpPacket>();
        if (ipPacket == null) return;

        // 处理TCP数据包
        var tcpPacket = packet.Extract<TcpPacket>();
        if (tcpPacket != null)
        {
            IPAddress localIp = ipPacket.SourceAddress;
            int localPort = tcpPacket.SourcePort;
            IPAddress remoteIp = ipPacket.DestinationAddress;
            int remotePort = tcpPacket.DestinationPort;

            string localProcess = GetProcessName(localIp, localPort, true);
            // 远程IP+端口的进程信息无法在本地获取,仅作展示
            string remoteProcess = "远程进程无法查询";

            Console.WriteLine($"TCP连接: {localIp}:{localPort} -> {remoteIp}:{remotePort} | 本地进程: {localProcess}");
            return;
        }

        // 处理UDP数据包
        var udpPacket = packet.Extract<UdpPacket>();
        if (udpPacket != null)
        {
            IPAddress localIp = ipPacket.SourceAddress;
            int localPort = udpPacket.SourcePort;
            IPAddress remoteIp = ipPacket.DestinationAddress;
            int remotePort = udpPacket.DestinationPort;

            string localProcess = GetProcessName(localIp, localPort, false);

            Console.WriteLine($"UDP连接: {localIp}:{localPort} -> {remoteIp}:{remotePort} | 本地进程: {localProcess}");
        }
    }

    private static string GetProcessName(IPAddress ip, int port, bool isTcp)
    {
        var map = isTcp ? _tcpMap : _udpMap;
        if (map.TryGetValue((ip, port), out int pid))
        {
            try
            {
                return System.Diagnostics.Process.GetProcessById(pid).ProcessName;
            }
            catch (Exception)
            {
                return $"PID {pid} 已退出";
            }
        }
        return "未知进程";
    }
}

注意事项

  • 运行程序需要管理员权限,因为获取端口-PID映射和网络数据包捕获都需要系统级权限
  • 端口映射是动态变化的,建议定时刷新(3-5秒一次),避免获取到过时信息
  • 远程IP+端口对应的进程信息无法在本地查询到,通常只关注本地IP+端口关联的进程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 08:44:21