C#を使ってTCPコネクション(セッション)の一覧を取得する方法です。
コマンドプロンプトで「netstat -a」したときに表示されるのと同じものです。
<技術資料>
TCP状態の一覧取得
GetTcpTable (MSDN Library)
<参考ソースコード>
Get TCP Information (VB.NET)
<C#ソースコード>
※VB.NETな人は、上記の参考ソースコードを見てください。
/* tcptable.cs */ /* version 0.02 */ using System; using System.Text; using System.Collections; using System.Runtime.InteropServices; namespace TcpView{ class TcpTableView{ //GetTcpTable APIのインポート [DllImport("iphlpapi.dll", CharSet=CharSet.Auto)] public extern static int GetTcpTable(IntPtr pTcpTable, ref int pdwSize, bool bOrder ); //GetTcpTable の戻り値 public const short NO_ERROR = 0; public const short ERROR_NOT_SUPPORTED = 50; public const short ERROR_INVALID_PARAMETER = 87; public const short ERROR_INSUFFICIENT_BUFFER = 112; /*MIB_TCPTABLE 構造体 [ StructLayout(LayoutKind.Sequential) ] public struct MIB_TCPTABLE{ public int dwNumEntries; public MIB_TCPROW[] table; } */ //MIB_TCPROW 構造体 [ StructLayout(LayoutKind.Sequential) ] public struct MIB_TCPROW{ public int dwState; public int dwLocalAddr; public int dwLocalPort; public int dwRemoteAddr; public int dwRemotePort; } //MIB_TCPROW.dwState 用定義 public const short MIB_TCP_STATE_CLOSED = 1; public const short MIB_TCP_STATE_LISTEN = 2; public const short MIB_TCP_STATE_SYN_SENT = 3; public const short MIB_TCP_STATE_SYN_RCVD = 4; public const short MIB_TCP_STATE_ESTAB = 5; public const short MIB_TCP_STATE_FIN_WAIT1 = 6; public const short MIB_TCP_STATE_FIN_WAIT2 = 7; public const short MIB_TCP_STATE_CLOSE_WAIT = 8; public const short MIB_TCP_STATE_CLOSING = 9; public const short MIB_TCP_STATE_LAST_ACK = 10; public const short MIB_TCP_STATE_TIME_WAIT = 11; public const short MIB_TCP_STATE_DELETE_TCB = 12; public static string[] StateStrings = {"", "CLOSED","LISTEN","SYN_SENT","SYN_RCVD","ESTABLISHED","FIN_WAIT1","FIN_WAIT2", "CLOSE_WAIT","CLOSING","LAST_ACK","TIME_WAIT","DELETE_TCB"}; //============================================================ public static void Main(){ ArrayList TcpTable = GetTcpTableView(); //結果を表示 for (int i = 0; i <= TcpTable.Count - 1; i++){ Console.Write(GetIpAddress(((TcpRow)TcpTable[i]).LocalAddr)); Console.Write(" "); Console.Write(GetPortNumber(((TcpRow)TcpTable[i]).LocalPort)); Console.Write(" "); Console.Write(GetIpAddress(((TcpRow)TcpTable[i]).RemoteAddr)); Console.Write(" "); Console.Write(GetPortNumber(((TcpRow)TcpTable[i]).RemotePort)); Console.Write(" "); Console.Write(StateStrings[((TcpRow)TcpTable[i]).State]); Console.WriteLine(""); } } public static ArrayList GetTcpTableView(){ int pdwSize = 0; IntPtr pTcpTable = IntPtr.Zero; //TcpTable用ポインタ GetTcpTable(pTcpTable, ref pdwSize, false); //pdwSizeを取得 pTcpTable = Marshal.AllocHGlobal(pdwSize); //メモリを割り当て try{ //TCPの一覧を取得 if (GetTcpTable(pTcpTable, ref pdwSize, true) == NO_ERROR){ int RowCount = Marshal.ReadInt32(pTcpTable); //MIB_TCPTABLE.dwNumEntriesを読み取り ArrayList TcpTable = new ArrayList(); //結果用リスト for (int i = 0; i<= RowCount - 1; i++){ //1列ずつ取得 IntPtr pTcpRow = new IntPtr(pTcpTable.ToInt32() + 4 + (i * Marshal.SizeOf(typeof(MIB_TCPROW)))); MIB_TCPROW _TcpRow = new MIB_TCPROW(); _TcpRow = (MIB_TCPROW)Marshal.PtrToStructure(pTcpRow, typeof(MIB_TCPROW)); //取得結果 TcpRow row = new TcpRow(); row.LocalAddr = _TcpRow.dwLocalAddr; row.LocalPort = _TcpRow.dwLocalPort; row.RemoteAddr = _TcpRow.dwRemoteAddr; row.RemotePort = _TcpRow.dwRemotePort; row.State = _TcpRow.dwState; //RemoteAddrが0の場合は、Remoteポートも0にする if (row.RemoteAddr == 0) row.RemotePort = 0; TcpTable.Add(row); } //for return TcpTable; } //if else return null; } //try finally{ Marshal.FreeHGlobal(pTcpTable); //メモリ開放 } } //gettcptableview private static string GetIpAddress(int Address){ byte[] IpParts = BitConverter.GetBytes(Address); StringBuilder builder = new StringBuilder(); builder.Append(IpParts[0].ToString()); builder.Append("."); builder.Append(IpParts[1].ToString()); builder.Append("."); builder.Append(IpParts[2].ToString()); builder.Append("."); builder.Append(IpParts[3].ToString()); return builder.ToString(); } private static int GetPortNumber(int Port){ return Port / 256 + (Port % 256) * 256; } } //class public struct TcpRow{ public int LocalAddr; public int LocalPort; public int RemoteAddr; public int RemotePort; public int State; } } //namespace |
<ソースのダウンロード>
tcptable v0.02
<解説>
TCPコネクションの一覧を取得するには、「GetTcpTable」Windows APIを使用します。
これはアンマネージドなので、iphlpapi.dllからインポートして使用します。さらにアンマネージドな構造体「MIB_TCPROW」を定義します。
WindowsAPIではポインタを使うことが多いのですが、GetTcpTableでは第1引数のpTcpTable、第2引数のpdwSizeがポインタです。
本来pTcpTableはMIB_TCPTABLE構造体を定義すべきですが、この構造体は.NET Frameworkでの扱いが難しいため、汎用的なポインタ「IntPtr」として定義しています。
pdwSizeをポインタとして扱うためには、参照渡しにします。refパラメータを付ければOKです。
アンマネージドな構造体を定義するには、構造体の上に「StructLayout」を記述します。