ARPテーブルの取得(F#) おまけもあるよ。
元ネタ:ARPテーブルの取得 (C#)(F#) - SIN@SAPPOROWORKSの覚書
http://d.hatena.ne.jp/spw0022/20111108/1320700838
SINさんがF#を書きまくっている今日この頃。F#の街札幌のF#りょくの高まりを感じざるを得ない。
F#らしい書き方かどうかはわかりませんが、SINさんのコードをベースにあまり深く考えずに。
コメント欄にお邪魔するには長いのでこちらで。
ARP(Address Resolution Protocol)テーブルの取得
#nowarn "9" "51" open System open System.Runtime.InteropServices open System.Linq [<DllImport("iphlpapi.dll")>] extern int GetIpNetTable(IntPtr pTcpTable, int *pdwSize, bool bOrder); [<Struct; StructLayout(LayoutKind.Sequential)>] type MIB_IPNETROW = val Index:int val PhysAddrLen:int [<MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)>] val PhysAddr:byte [] val Addr:int val Type:int let ipstr(addr:int)= let b = BitConverter.GetBytes(addr) sprintf "%d.%d.%d.%d" b.[0] b.[1] b.[2] b.[3] let macstr(m:byte []) = sprintf "%02x-%02x-%02x-%02x-%02x-%02x" m.[0] m.[1] m.[2] m.[3] m.[4] m.[5] let typeStr = ["";"その他";"無効";"動的";"静的"] //取得部分 let ar = let mutable size = 0 GetIpNetTable(IntPtr.Zero, &&size, true) |> ignore let p = Marshal.AllocHGlobal(size) if GetIpNetTable(p, &&size, true) = 0 then let end' = Marshal.ReadInt32(p) - 1 let result = let step = Marshal.SizeOf(typeof<MIB_IPNETROW>) let getPtr = let ptr' = ref (IntPtr.Add(p, 4)) (fun num -> if num=0 then !ptr' else ptr':=IntPtr.Add(!ptr',step); !ptr') [0..end'] |> List.map (fun x -> getPtr x) |> List.map (fun ptr -> Marshal.PtrToStructure(ptr, typeof<MIB_IPNETROW>) :?> MIB_IPNETROW) Marshal.FreeHGlobal(p) result else [] //出力部分 printfn "インデックス\tインターネット アドレス\t物理アドレス\t種類" ar |> List.toSeq |> Seq.groupBy (fun n -> n.Index) |> Seq.iter (fun (i,ms) -> printfn "\nインターフェース:0x%x\n インターネット アドレス\t物理アドレス\t種類" i ms |> Seq.iter (fun m -> printfn " %-15s\t%s\t%s" <| ipstr(m.Addr) <| macstr(m.PhysAddr) <| typeStr.[m.Type])) printfn "何かのキーを押してください。" Console.ReadKey() |> ignore
■主な変更点とかモロモロ
- ワーニングの波線が残り続けるのは、精神衛生上アレなので #nowarn で非表示に。
- 取得部分をひとまとめの関数に。
- なるべく、みゅーたぶり(mutableを使い)たくはないので、そのあたりをいじる。
- 「for 〜 in 〜 do 〜」を利用することは、決してわるいことではありません。が、F#ではSeqモジュールを利用してLINQのノリで書ける。
- 元ネタ「ar.Where(fun (x:MIB_IPNETROW) -> x.Index=i.Key)」で再度絞り込みする必要はなく、arのGroupByした結果をそのまま利用して結果を出力する。
- 前方パイプライン演算子には負けますが、後方パイプライン演算子もなかなかかわいいです。
- ふつうのF#erなので、奇をてらったへんたいコードは書きません。
おまけ
趣旨からはだいぶズレますが、コマンドラインからコマンドを実行して取得した値をそのまま書き出すズルしてみたり:p
open System let filename = Environment.GetEnvironmentVariable("ComSpec") let arguments = @"/c arp -a" let psi = new Diagnostics.ProcessStartInfo(filename, arguments, CreateNoWindow = true, UseShellExecute = false, RedirectStandardInput = false, RedirectStandardOutput = true) let p = Diagnostics.Process.Start(psi) p.WaitForExit() let results = p.StandardOutput.ReadToEnd() printfn "%s" results Console.ReadKey () |> ignore
これはひどいw