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」を記述します。