C#实现netstat的功能

news/2024/5/17 16:46:11 标签: C#, netstat, TCP, connection, pid
核心思想是调用 WinAPI 中的


GetExtendedTcpTable 方法来获取所有活动的 TCP 连接的信息,包括进程ID等等,主要实现如下:

TcpConnectionTableHelper.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace TcpConnectionMonitor
{
    public class TcpConnectionTableHelper
    {
        [DllImport("Ws2_32.dll")]
        static extern ushort ntohs(ushort netshort);

        [DllImport("iphlpapi.dll", SetLastError = true)]
        static extern uint GetExtendedTcpTable(IntPtr pTcpTable, ref int dwOutBufLen, bool sort, int ipVersion, TCP_TABLE_TYPE tblClass, int reserved);

        [StructLayout(LayoutKind.Sequential)]
        public struct MIB_TCPROW_OWNER_PID
        {
            public uint state;
            public uint localAddr;
            public byte localPort1;
            public byte localPort2;
            public byte localPort3;
            public byte localPort4;
            public uint remoteAddr;
            public byte remotePort1;
            public byte remotePort2;
            public byte remotePort3;
            public byte remotePort4;
            public int owningPid;

            public ushort LocalPort
            {
                get
                {
                    return BitConverter.ToUInt16(new byte[2] { localPort2, localPort1 }, 0);
                }
            }

            public ushort RemotePort
            {
                get
                {
                    return BitConverter.ToUInt16(new byte[2] { remotePort2, remotePort1 }, 0);
                }
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct MIB_TCPTABLE_OWNER_PID
        {
            public uint dwNumEntries;
            MIB_TCPROW_OWNER_PID table;
        }

        public static string GetIpAddress(long ipAddrs)
        {
            try
            {
                System.Net.IPAddress ipAddress = new System.Net.IPAddress(ipAddrs);
                return ipAddress.ToString();
            }
            catch { return ipAddrs.ToString(); }

        }

        public static ushort GetTcpPort(int tcpPort)
        {
            return ntohs((ushort)tcpPort);
        }

        public static MIB_TCPROW_OWNER_PID[] GetAllTcpConnections()
        {
            MIB_TCPROW_OWNER_PID[] tcpConnectionRows;
            int AF_INET = 2;    // IPv4
            int buffSize = 0;

            // use WinAPI GetExtendedTcpTable to query all active tcp connection information
            uint ret = GetExtendedTcpTable(IntPtr.Zero, ref buffSize, true, AF_INET, TCP_TABLE_TYPE.TCP_TABLE_OWNER_PID_ALL, 0);
            if (ret != 0 && ret != 122) // 122 means insufficient buffer size
            {
                throw new Exception("Error occurred when trying to query tcp table, return code: " + ret);
            }
            IntPtr buffTable = Marshal.AllocHGlobal(buffSize);

            try
            {
                ret = GetExtendedTcpTable(buffTable, ref buffSize, true, AF_INET, TCP_TABLE_TYPE.TCP_TABLE_OWNER_PID_ALL, 0);
                if (ret != 0)
                {
                    throw new Exception("Error occurred when trying to query tcp table, return code: " + ret);
                }

                // get the number of entries in the table
                MIB_TCPTABLE_OWNER_PID table = (MIB_TCPTABLE_OWNER_PID)Marshal.PtrToStructure(buffTable, typeof(MIB_TCPTABLE_OWNER_PID));
                IntPtr rowPtr = (IntPtr)((long)buffTable + Marshal.SizeOf(table.dwNumEntries));
                tcpConnectionRows = new MIB_TCPROW_OWNER_PID[table.dwNumEntries];

                for (int i = 0; i < table.dwNumEntries; i++)
                {
                    MIB_TCPROW_OWNER_PID tcpRow = (MIB_TCPROW_OWNER_PID)Marshal.PtrToStructure(rowPtr, typeof(MIB_TCPROW_OWNER_PID));
                    tcpConnectionRows[i] = tcpRow;
                    rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(tcpRow));
                }
            }
            finally
            {
                // free memory
                Marshal.FreeHGlobal(buffTable);
            }
            return tcpConnectionRows;
        }
    }
}

public enum TCP_TABLE_TYPE : int
{
    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
}

public enum TCP_CONNECTION_STATE : int
{
    CLOSED = 1,
    LISTENING,
    SYN_SENT,
    SYN_RCVD,
    ESTABLISHED,
    FIN_WAIT_1,
    FIN_WAIT_2,
    CLOSE_WAIT,
    CLOSING,
    LAST_ACK,
    TIME_WAIT,
    DELETE_TCP
};


Program.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TcpConnectionMonitor
{
    class Program
    {
        static void Main(string[] args)
        {
            MonitorTcpConnections();
        }

        static void MonitorTcpConnections()
        {
            Console.WriteLine("Proto  Local Address          Foreign Address        State           PID");
            List<String> rows = new List<string>();
            while (true)
            {
                int windowTop = Console.WindowTop;  //in order to keep console scroll bar stay
                TcpConnectionTableHelper.MIB_TCPROW_OWNER_PID[] tcpProgressInfoTable = TcpConnectionTableHelper.GetAllTcpConnections();
                int tableRowCount = tcpProgressInfoTable.Length;
                for (int i = 0; i < tableRowCount; i++)
                {
                    TcpConnectionTableHelper.MIB_TCPROW_OWNER_PID row = tcpProgressInfoTable[i];
                    string source = string.Format("{0}:{1}", TcpConnectionTableHelper.GetIpAddress(row.localAddr), row.LocalPort);
                    string dest = string.Format("{0}:{1}", TcpConnectionTableHelper.GetIpAddress(row.remoteAddr), row.RemotePort);
                    string outputRow = string.Format("{0, -7}{1, -23}{2, -23}{3, -16}{4}", "TCP", source, dest, (TCP_CONNECTION_STATE)row.state, row.owningPid);
                    if (rows.Count < i + 1)
                    {
                        Console.SetCursorPosition(0, i + 1);
                        Console.WriteLine("{0, -80}", outputRow);
                        rows.Add(outputRow);
                    }
                    else if (rows[i] != outputRow)
                    {
                        rows[i] = outputRow;
                        Console.SetCursorPosition(0, i + 1);
                        Console.WriteLine("{0, -80}", outputRow);
                    }
                }
                if (rows.Count > tableRowCount)
                {
                    int linesToBeCleared = rows.Count - tableRowCount;
                    rows.RemoveRange(tableRowCount, linesToBeCleared);
                    for (int i = 0; i < linesToBeCleared + 1; i++)
                    {
                        Console.WriteLine("{0, -80}", " ");
                    }
                }
                Console.SetWindowPosition(0, windowTop);    //in order to keep console scroll bar stay
                Thread.Sleep(100);
            }
        }
    }
}


实现的效果是每 100ms 获取一次活跃 TCP 连接的状态,也就是说每秒大概会刷新10次,为了避免由于刷新频率过快导致闪烁的问题,通过调用 Console.SetCursorPosition 来对变化的数据进行部分刷新,同时为了避免滚动条存在时,Console 指针引起滚动条自动滚动到最后一行,使用 SetWindowPosition 来固定滚动条的位置。

输出结果举例:



http://www.niftyadmin.cn/n/878038.html

相关文章

Linux ext2, ext3, ext4 文件系统解读[1]

ext2 文件系统结构分析&#xff1a; 首先来看一下ext2文件系统的结构示意图&#xff1a; Block&#xff1a; 对于ext2文件系统来说&#xff0c;硬盘分区首先被分割为一个一个的“Block”&#xff0c;每个Block就是实际用来存储数据的单元&#xff0c;大小相同&#xff0c;Block…

Linux ext2, ext3, ext4 文件系统解读[2]

&#xfeff;&#xfeff;目录与文件&#xff1a; 从前面Inode的结构中我们可以看到&#xff0c;其中并没有定义文件名称&#xff0c;文件名称实际是存放在目录中的&#xff0c;目录也是一类特殊的文件&#xff0c;在ext2文件系统中&#xff0c;目录是由ext2_dir_entry结构组成…

Linux ext2, ext3, ext4 文件系统解读[3]

&#xfeff;&#xfeff;mke2fs.conf 配置文件说明以及格式化&#xff1a; mke2fs.conf文件位于/etc/mke2fs.conf&#xff08;不同系统位置可能有区别&#xff0c;这里以CentOS 6.5为例&#xff09;&#xff0c;我们看一下其中的内容&#xff1a; [defaults] base_features …

Mongo中_id与java实体类中对应关系

_id作为mongo数据库中集合里面每个文档的唯一标识&#xff0c;我们在java中进行增删改查操作中有时候不可避免的需要使用到。但是_id在文档中的定义类型为Objectid类型&#xff0c;那我们在java实体类中又该建立何种类型与之对应呢&#xff1f; 直接新建属性id,类型为String就…

Linux ext2, ext3, ext4 文件系统解读[4]

&#xfeff;&#xfeff;ext2 ext3 ext4 文件系统的区别&#xff1a; ext2为非日志文件系统&#xff0c;即在文件系统的运行期间不会记录写操作的日志&#xff0c;这就有一个很大的弊端&#xff0c;即文件系统只能单纯依靠Inode和Data Block的Bitmap来确定数据写入的状态。 我…

Linux ext2, ext3, ext4 文件系统解读[5]

&#xfeff;&#xfeff;mount 过程&#xff1a; 每个文件系统都有独立的Super Block&#xff0c;Inode&#xff0c;Data Block&#xff0c;如果我们要访问一个文件系统中的内容&#xff0c;或者向文件系统中写入数据&#xff0c;那么首先需要让系统能够找到文件系统的入口。在…

windows下头骨剔除软件_Windows下学习C语言有哪些集成开发软件?

前言初学者学习C语言遇到的最大困难想必就是搭建环境了&#xff0c;相当多的初学者就是被搭建环境导致放弃了学习编程&#xff0c;就我自己的经验而言&#xff0c;初学编程不应该受限于环境&#xff0c;使用成熟好用的环境就可以了&#xff0c;之后熟悉一些可以在慢慢探究。想到…

Angular项目linux服务器部署

首先将angular项目运行环境配置好&#xff0c;和本地基本类似&#xff1a;如node.js&#xff0c;npm&#xff0c;angular/cli等环境。配置好之后直接将本地的angular项目copy到服务器上来&#xff0c;然后 ng serve如果出现报错&#xff1a; Error: Missing binding /opt/pro…