---
lang: ja-jp
breaks: true
---
# C# netstat の結果と同じものを取得したい 2021-04-30
## System.Net.NetworkInformation を利用
> C#でnetstatのような機能を実装してみる
> https://code-examples-ja.hateblo.jp/entry/2015/01/22/C%23%E3%81%A7netstat%E3%81%AE%E3%82%88%E3%81%86%E3%81%AA%E6%A9%9F%E8%83%BD%E3%82%92%E5%AE%9F%E8%A3%85%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B
この方法は、アプリケーションのプロセスIDは取得出来ない。
```csharp=
static void Main_CS()
{
var ip = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties();
Console.WriteLine("プロトコル\tローカルアドレス\t外部アドレス\t状態");
foreach (TcpConnectionInformation tcp in ip.GetActiveTcpConnections())
{
if (tcp.State == System.Net.NetworkInformation.TcpState.Established)
{
Console.Write("TCP" + "\t"); //express only tcp
Console.Write(tcp.LocalEndPoint.Address + ":" + tcp.LocalEndPoint.Port + "\t");
Console.Write(tcp.RemoteEndPoint.Address + ":" + tcp.RemoteEndPoint.Port + "\t");
Console.Write(tcp.State);
Console.WriteLine();
}
}
Console.ReadLine();
}
```
## Win32API を利用(IPv6非対応)
> TCPコネクションの一覧取得(プロセスID含む) (C#)(F#)
> http://furuya02.hatenablog.com/entry/20111104/1399766889
> otykier/TabularEditor
> TabularEditor/TabularEditor/UIServices/ManagedIpHelper.cs
> https://github.com/otykier/TabularEditor/blob/494c0198d581882d6d3165f9dc98eb5d6290c817/TabularEditor/UIServices/ManagedIpHelper.cs
```csharp=
enum TCP_TABLE_CLASS
{
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
};
[DllImport("iphlpapi.dll")]
extern static int GetExtendedTcpTable(IntPtr pTcpTable, ref int pdwSize, bool bOrder, uint ulAf, TCP_TABLE_CLASS TableClass, int Reserved);
[StructLayout(LayoutKind.Sequential)]
public struct MIB_TCPROW_OWNER_PID
{
/// <summary>
/// TCP接続の状態です。このメンバーには,Iprtrmib.hヘッダーファイルで定義されている値のいずれかを指定できます。
///
/// Windows Vista以降のWindows SDKでは,ヘッダーファイルの構成が変更されています。
/// このメンバーには、Iprtrmib.hではなく、Tcpmib.hヘッダーファイルで定義されたMIB_TCP_STATE列挙の値のいずれかを指定できます。
/// なお,Tcpmib.hヘッダファイルはIprtrmib.hに自動的にインクルードされ,Iprtrmib.hはIphlpapi.hヘッダファイルに自動的にインクルードされます。
/// Tcpmib.hとIprtrmib.hのヘッダファイルは、決して直接使用しないでください。
/// </summary>
public int State;
/// <summary>
/// ローカルコンピュータ上のTCP接続用のローカルIPv4アドレスです。値がゼロの場合、リスナーはどのインターフェースでも接続を受け入れることができます。
/// </summary>
public int LocalAddr;
/// <summary>
/// ローカルコンピューターでのTCP接続のためのネットワークバイトオーダーのローカルポート番号。
/// </summary>
public int LocalPort;
/// <summary>
/// リモートコンピュータ上のTCP接続のIPv4アドレスです。dwStateメンバがMIB_TCP_STATE_LISTENの場合、この値は意味を持ちません。
/// </summary>
public int RemoteAddr;
/// <summary>
/// リモートコンピュータ上のTCP接続用のネットワークバイトオーダーのリモートポート番号。dwStateメンバがMIB_TCP_STATE_LISTENの場合、このメンバは意味を持ちません。
/// </summary>
public int RemotePort;
/// <summary>
/// このTCPコネクションのコンテキスト・バインドを発行したプロセスのPIDです。
/// </summary>
public int OwningPid;
}
public enum MIB_TCP_STATE : int
{
/// <summary>
/// TCPコネクションはCLOSED状態であり、コネクションの状態を全く表していません。
/// </summary>
CLOSED = 1,
/// <summary>
/// TCP接続はLISTEN状態で、任意のリモートTCPおよびポートからの接続要求を待っています。
/// </summary>
LISTENING = 2,
/// <summary>
/// TCPコネクションは、接続要求(SYNパケット)を送信した後、一致する接続要求を待っているSYN-SENT状態にあります。
/// </summary>
SYN_SENT = 3,
/// <summary>
/// TCPコネクションは、接続要求(SYNパケット)を受信して送信した後、接続要求の確認応答を待っているSYN-RECEIVED状態にあります。
/// </summary>
SYN_RCVD = 4,
/// <summary>
/// TCP接続はESTABLISHED状態で、接続が開いており、受信したデータをユーザーに届けることができることを表しています。
/// この状態は、TCPコネクションのデータ転送フェーズの通常の状態です。
/// </summary>
ESTABLISHED = 5,
/// <summary>
/// TCP接続はFIN-WAIT-1状態で、リモートTCPからの接続終了要求、または以前に送信した接続終了要求に対する確認応答を待っています。
/// </summary>
FIN_WAIT1 = 6,
/// <summary>
/// TCP接続はFIN-WAIT-2状態で、リモートTCPからの接続終了要求を待っています。
/// </summary>
FIN_WAIT2 = 7,
/// <summary>
/// TCP接続はCLOSE-WAIT状態で、ローカルユーザーからの接続終了要求を待っています。
/// </summary>
CLOSE_WAIT = 8,
/// <summary>
/// TCP接続はCLOSING状態で、リモートTCPからの接続終了要求の確認応答を待っています。
/// </summary>
CLOSING = 9,
/// <summary>
/// TCP接続はLAST-ACK状態で、以前にリモートTCPに送信した接続終了要求の確認応答を待っています(これには、その接続終了要求の確認応答も含まれています)。
/// </summary>
LAST_ACK = 10,
/// <summary>
/// TCP接続はTIME-WAIT状態で、リモートTCPが接続終了要求の確認応答を受け取ったことを確認するために十分な時間が経過するのを待っています。
/// </summary>
TIME_WAIT = 11,
/// <summary>
/// TCP接続は、各TCPエントリの情報を保持するためのデータ構造であるTCB(Transmission Control Block)の削除を表すdelete TCB状態になっています。
/// </summary>
DELETE_TCB = 12,
}
public const uint AF_INET = 2; // internetwork: UDP, TCP, etc.
public const uint AF_INET6 = 23; // Internetwork Version 6
static void Main_Win32API()
{
Console.WriteLine("プロトコル\tローカルアドレス\t外部アドレス\t状態\tPID");
uint ulAf = AF_INET;
//uint ulAf = AF_INET6;
int size = 0;
//必要サイズの取得
GetExtendedTcpTable(IntPtr.Zero, ref size, true, ulAf, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL, 0);
IntPtr p = Marshal.AllocHGlobal(size);//メモリ割当て
try
{
//TCPテーブルの取得
if (GetExtendedTcpTable(p, ref size, true, ulAf, TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL, 0) == 0)
{
var num = Marshal.ReadInt32(p);//MIB_TCPTABLE_OWNER_PID.dwNumEntries(データ数)
var ptr = IntPtr.Add(p, 4);
for (int i = 0; i < num; i++)
{
MIB_TCPROW_OWNER_PID o = (MIB_TCPROW_OWNER_PID)Marshal.PtrToStructure(ptr, typeof(MIB_TCPROW_OWNER_PID));
if (o.RemoteAddr == 0)
{
//RemoteAddrが0の場合は、RemotePortも0にする
o.RemotePort = 0;
}
Console.WriteLine(
string.Format("TCP\t{0}:{1}\t{2}:{3}\t{4}\t{5}",
ipstr(o.LocalAddr, ulAf),
htons(o.LocalPort),
ipstr(o.RemoteAddr, ulAf),
htons(o.RemotePort),
(MIB_TCP_STATE)o.State,
o.OwningPid
));
ptr = IntPtr.Add(ptr, Marshal.SizeOf(typeof(MIB_TCPROW_OWNER_PID)));//次のデータ
}
}
Console.WriteLine();
}
finally
{
Marshal.FreeHGlobal(p); //メモリ開放
}
}
private static string ipstr(int addr, uint ulAf)
{
if (ulAf == AF_INET)
{
var b = BitConverter.GetBytes(addr);
return string.Format("{0}.{1}.{2}.{3}", b[0], b[1], b[2], b[3]);
}
else if (ulAf == AF_INET6)
{
throw new Exception("Not supported.");
}
throw new Exception("Not supported.");
}
private static int htons(int i)
{
var tmp = (((0x000000ff & i) << 8) + ((0x0000ff00 & i) >> 8))
+ ((0x00ff0000 & i) << 8) + ((0xff000000 & i) >> 8);
return (int)tmp;
}
```
###### tags: `C#` `netstat`