SIN@SAPPOROWORKSの覚書

C#を中心に、夜な夜な試行錯誤したコードの記録です。

TCPコネクションの一覧取得 (C#)(F#)


TCPコネクションの一覧は、iphlpapi.dllのGetTcpTable()で取得することが可能です。
GetTcpTable()で取得するデータサイズは、最初にnullを指定して確認します。

コマンドラインから「netstat -an -p TCP」としたときの出力と同じものです。

C#サンプル

using System;
using System.Runtime.InteropServices;

namespace Exsample {
    class Program {
        [DllImport("iphlpapi.dll")]
        extern static int GetTcpTable(IntPtr pTcpTable, ref int pdwSize, bool bOrder);

        [StructLayout(LayoutKind.Sequential)]
        public struct MIB_TCPROW {
            public int State;
            public int LocalAddr;
            public int LocalPort;
            public int RemoteAddr;
            public int RemotePort;
        }

        public static string[] StateStrings = {
            "", "CLOSED","LISTENING","SYN_SENT","SYN_RCVD","ESTABLISHED","FIN_WAIT1",
            "FIN_WAIT2","CLOSE_WAIT","CLOSING","LAST_ACK","TIME_WAIT","DELETE_TCB"};

        static void Main(string[] args) {
            Console.WriteLine("プロトコルtローカルアドレスt外部アドレスt状態");
            var size = 0;
            GetTcpTable(IntPtr.Zero, ref size, false);//必要サイズの取得
            var p = Marshal.AllocHGlobal(size);//メモリ割当て
            if (GetTcpTable(p, ref size, true) == 0) {//TCPテーブルの取得
                var num = Marshal.ReadInt32(p);//MIB_TCPTABLE.dwNumEntries(データ数)
                var ptr = IntPtr.Add(p, 4);
                for (int i = 0; i < num; i++) {
                    var o = (MIB_TCPROW)Marshal.PtrToStructure(ptr, typeof(MIB_TCPROW));
                    if (o.RemoteAddr == 0)
                        o.RemotePort = 0;//RemoteAddrが0の場合は、RemotePortも0にする
                    Console.WriteLine(string.Format("TCPt{0}:{1}t{2}:{3}t{4}"
                        , ipstr(o.LocalAddr),htons(o.LocalPort)
                        , ipstr(o.RemoteAddr),htons(o.RemotePort)
                        , StateStrings[o.State]));
                    ptr = IntPtr.Add(ptr, Marshal.SizeOf(typeof(MIB_TCPROW)));//次のデータ
                }
                Marshal.FreeHGlobal(p);  //メモリ開放
            }
            Console.WriteLine();
            Console.WriteLine("何かのキーを押してください。");
            Console.ReadKey();
        }

        private static string ipstr(int addr) {
            var b = BitConverter.GetBytes(addr);
            return string.Format("{0}.{1}.{2}.{3}",b[0],b[1],b[2],b[3]);
        }
        
        public static int htons(int i) {
            var tmp = (((0x000000ff&i) << 8) + ((0x0000ff00&i) >> 8)) + ((0x00ff0000&i)<<8) + ((0xff000000&i)>>8);
            return (int)tmp;
        }
    }
}

F#サンプル

open System
open System.Runtime.InteropServices

let ipstr(addr:int)=
    let b = BitConverter.GetBytes(addr)
    sprintf "%d.%d.%d.%d" b.[0] b.[1] b.[2] b.[3] 
    
let htons(i) =  
    (((0x000000ff&&&i) <<< 8) + ((0x0000ff00&&&i) >>> 8)) + ((0x00ff0000&&&i)<<<8) + ((0xff000000&&&i)>>>8)

[<DllImport("iphlpapi.dll")>]
extern int GetTcpTable(IntPtr pTcpTable,int *pdwSize,bool bOrder)

[<StructLayout(LayoutKind.Sequential)>]
type MIB_TCPROW =
    struct
        val State : int
        val LocalAddr : int
        val LocalPort : int
        val RemoteAddr: int
        val mutable RemotePort: int
    end

let StateStrings = [
            ""; "CLOSED";"LISTENING";"SYN_SENT";"SYN_RCVD";"ESTABLISHED";"FIN_WAIT1";
            "FIN_WAIT2";"CLOSE_WAIT";"CLOSING";"LAST_ACK";"TIME_WAIT";"DELETE_TCB"]

printfn "プロトコルtローカルアドレスt外部アドレスt状態"

let mutable size = 0
GetTcpTable(IntPtr.Zero,&&size,false)//必要サイズの取得
let p = Marshal.AllocHGlobal(size)//メモリ割当て
if GetTcpTable(p, &&size, true) = 0 then //TCPテーブルの取得
    let num = Marshal.ReadInt32(p)//MIB_TCPTABLE.dwNumEntries(データ数)
    let mutable ptr = IntPtr.Add(p,4)
    for i in [0..num-1] do
        let mutable o = Marshal.PtrToStructure(ptr, typeof<MIB_TCPROW>):?>MIB_TCPROW
        if o.RemoteAddr=0 then o.RemotePort<-0//RemoteAddrが0の場合は、RemotePortも0にする
        printfn "TCPt%s:%dt%s:%dt%s" 
            (ipstr(o.LocalAddr)) (htons(o.LocalPort))
            (ipstr(o.RemoteAddr)) (htons(o.RemotePort))
            (StateStrings.[o.State])
        ptr <- IntPtr.Add(ptr, Marshal.SizeOf(typeof<MIB_TCPROW>))//次のデータ
    Marshal.FreeHGlobal(p);  //メモリ開放
printfn ""
printfn "何かのキーを押してください。"
Console.ReadKey() |> ignore