点晴MIS问题教程区 加入收藏
问题搜索
 您的位置:点晴MIS系统问题答疑『 经验分享&问题答疑 』浏览当前教程  
  

  网站搜索
  搜索范围: 搜索方式: 关键词(可用空格分开)  

  作者及文章信息: 本文热度:70 % 
admin

积分:72194
等级:网站管理员
文数:13967
注册:2004-7-20

 信息   主页   编辑     

楼 顶 

 C#实现netstat的功能获取所有连接到本机的外部IP地址及端口


核心思想是调用 WinAPI 中的 GetExtendedTcpTable 方法来获取所有活动的 TCP 连接的信息,包括进程ID等等,主要实现如下:

TcpConnectionTableHelper.cs:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.InteropServices;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. namespace TcpConnectionMonitor
  8. {
  9. public class TcpConnectionTableHelper
  10. {
  11. [DllImport("Ws2_32.dll")]
  12. static extern ushort ntohs(ushort netshort);
  13. [DllImport("iphlpapi.dll", SetLastError = true)]
  14. static extern uint GetExtendedTcpTable(IntPtr pTcpTable, ref int dwOutBufLen, bool sort, int ipVersion, TCP_TABLE_TYPE tblClass, int reserved);
  15. [StructLayout(LayoutKind.Sequential)]
  16. public struct MIB_TCPROW_OWNER_PID
  17. {
  18. public uint state;
  19. public uint localAddr;
  20. public byte localPort1;
  21. public byte localPort2;
  22. public byte localPort3;
  23. public byte localPort4;
  24. public uint remoteAddr;
  25. public byte remotePort1;
  26. public byte remotePort2;
  27. public byte remotePort3;
  28. public byte remotePort4;
  29. public int owningPid;
  30. public ushort LocalPort
  31. {
  32. get
  33. {
  34. return BitConverter.ToUInt16(new byte[2] { localPort2, localPort1 }, 0);
  35. }
  36. }
  37. public ushort RemotePort
  38. {
  39. get
  40. {
  41. return BitConverter.ToUInt16(new byte[2] { remotePort2, remotePort1 }, 0);
  42. }
  43. }
  44. }
  45. [StructLayout(LayoutKind.Sequential)]
  46. public struct MIB_TCPTABLE_OWNER_PID
  47. {
  48. public uint dwNumEntries;
  49. MIB_TCPROW_OWNER_PID table;
  50. }
  51. public static string GetIpAddress(long ipAddrs)
  52. {
  53. try
  54. {
  55. System.Net.IPAddress ipAddress = new System.Net.IPAddress(ipAddrs);
  56. return ipAddress.ToString();
  57. }
  58. catch { return ipAddrs.ToString(); }
  59. }
  60. public static ushort GetTcpPort(int tcpPort)
  61. {
  62. return ntohs((ushort)tcpPort);
  63. }
  64. public static MIB_TCPROW_OWNER_PID[] GetAllTcpConnections()
  65. {
  66. MIB_TCPROW_OWNER_PID[] tcpConnectionRows;
  67. int AF_INET = 2; // IPv4
  68. int buffSize = 0;
  69. // use WinAPI GetExtendedTcpTable to query all active tcp connection information
  70. uint ret = GetExtendedTcpTable(IntPtr.Zero, ref buffSize, true, AF_INET, TCP_TABLE_TYPE.TCP_TABLE_OWNER_PID_ALL, 0);
  71. if (ret != 0 && ret != 122) // 122 means insufficient buffer size
  72. {
  73. throw new Exception("Error occurred when trying to query tcp table, return code: " + ret);
  74. }
  75. IntPtr buffTable = Marshal.AllocHGlobal(buffSize);
  76. try
  77. {
  78. ret = GetExtendedTcpTable(buffTable, ref buffSize, true, AF_INET, TCP_TABLE_TYPE.TCP_TABLE_OWNER_PID_ALL, 0);
  79. if (ret != 0)
  80. {
  81. throw new Exception("Error occurred when trying to query tcp table, return code: " + ret);
  82. }
  83. // get the number of entries in the table
  84. MIB_TCPTABLE_OWNER_PID table = (MIB_TCPTABLE_OWNER_PID)Marshal.PtrToStructure(buffTable, typeof(MIB_TCPTABLE_OWNER_PID));
  85. IntPtr rowPtr = (IntPtr)((long)buffTable + Marshal.SizeOf(table.dwNumEntries));
  86. tcpConnectionRows = new MIB_TCPROW_OWNER_PID[table.dwNumEntries];
  87. for (int i = 0; i < table.dwNumEntries; i++)
  88. {
  89. MIB_TCPROW_OWNER_PID tcpRow = (MIB_TCPROW_OWNER_PID)Marshal.PtrToStructure(rowPtr, typeof(MIB_TCPROW_OWNER_PID));
  90. tcpConnectionRows[i] = tcpRow;
  91. rowPtr = (IntPtr)((long)rowPtr + Marshal.SizeOf(tcpRow));
  92. }
  93. }
  94. finally
  95. {
  96. // free memory
  97. Marshal.FreeHGlobal(buffTable);
  98. }
  99. return tcpConnectionRows;
  100. }
  101. }
  102. }
  103. public enum TCP_TABLE_TYPE : int
  104. {
  105. TCP_TABLE_BASIC_LISTENER,
  106. TCP_TABLE_BASIC_CONNECTIONS,
  107. TCP_TABLE_BASIC_ALL,
  108. TCP_TABLE_OWNER_PID_LISTENER,
  109. TCP_TABLE_OWNER_PID_CONNECTIONS,
  110. TCP_TABLE_OWNER_PID_ALL,
  111. TCP_TABLE_OWNER_MODULE_LISTENER,
  112. TCP_TABLE_OWNER_MODULE_CONNECTIONS,
  113. TCP_TABLE_OWNER_MODULE_ALL
  114. }
  115. public enum TCP_CONNECTION_STATE : int
  116. {
  117. CLOSED = 1,
  118. LISTENING,
  119. SYN_SENT,
  120. SYN_RCVD,
  121. ESTABLISHED,
  122. FIN_WAIT_1,
  123. FIN_WAIT_2,
  124. CLOSE_WAIT,
  125. CLOSING,
  126. LAST_ACK,
  127. TIME_WAIT,
  128. delete_TCP
  129. };


Program.cs:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace TcpConnectionMonitor
  8. {
  9. class Program
  10. {
  11. static void Main(string[] args)
  12. {
  13. MonitorTcpConnections();
  14. }
  15. static void MonitorTcpConnections()
  16. {
  17. Console.WriteLine("Proto Local Address Foreign Address State PID");
  18. List<String> rows = new List<string>();
  19. while (true)
  20. {
  21. int windowTop = Console.WindowTop; //in order to keep console scroll bar stay
  22. TcpConnectionTableHelper.MIB_TCPROW_OWNER_PID[] tcpProgressInfoTable = TcpConnectionTableHelper.GetAllTcpConnections();
  23. int tableRowCount = tcpProgressInfoTable.Length;
  24. for (int i = 0; i < tableRowCount; i++)
  25. {
  26. TcpConnectionTableHelper.MIB_TCPROW_OWNER_PID row = tcpProgressInfoTable[i];
  27. string source = string.Format("{0}:{1}", TcpConnectionTableHelper.GetIpAddress(row.localAddr), row.LocalPort);
  28. string dest = string.Format("{0}:{1}", TcpConnectionTableHelper.GetIpAddress(row.remoteAddr), row.RemotePort);
  29. string outputRow = string.Format("{0, -7}{1, -23}{2, -23}{3, -16}{4}", "TCP", source, dest, (TCP_CONNECTION_STATE)row.state, row.owningPid);
  30. if (rows.Count < i + 1)
  31. {
  32. Console.SetCursorPosition(0, i + 1);
  33. Console.WriteLine("{0, -80}", outputRow);
  34. rows.Add(outputRow);
  35. }
  36. else if (rows[i] != outputRow)
  37. {
  38. rows[i] = outputRow;
  39. Console.SetCursorPosition(0, i + 1);
  40. Console.WriteLine("{0, -80}", outputRow);
  41. }
  42. }
  43. if (rows.Count > tableRowCount)
  44. {
  45. int linesToBeCleared = rows.Count - tableRowCount;
  46. rows.RemoveRange(tableRowCount, linesToBeCleared);
  47. for (int i = 0; i < linesToBeCleared + 1; i++)
  48. {
  49. Console.WriteLine("{0, -80}", " ");
  50. }
  51. }
  52. Console.SetWindowPosition(0, windowTop); //in order to keep console scroll bar stay
  53. Thread.Sleep(100);
  54. }
  55. }
  56. }
  57. }

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

输出结果举例:



该文章在 2022/11/17 10:05:16 编辑过

  离 线  2022/11/17 10:05:15 
  本文章共有 0 页, 0 张回文,每页有 10 张回文 >> [ ]
页码:  
Copyright 2010-2022 ClickSun All Rights Reserved