C#實現netstat的功能

來源:互聯網
上載者:User
核心思想是調用 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 來固定捲軸的位置。

輸出結果舉例:


相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.