(C#)WPFでLAN内のIP(IPv4)を一覧表示する
ローカルエリアネットワーク内のIPを一覧表示するプログラムを書きました。
なんかいい感じのメソッド読んでやれば楽勝でしょ、とか思ってましたけどそんなことはありませんでした…
目次
当初の想定
C#
にそういうLAN
をスキャンしてくれるメソッドはあるんじゃないかなー、と勝手に期待してましたけど、
どうやらそういうのはないみたいでした。。。
ま、まあでもブロードキャストアドレス
にping
を打ってやればいいのと違うかなー、、、と思って進めるとどうもこれも駄目。
というのも、Windows
がそもそもデフォルトだとping
に反応しないみたいで、テストマシンが検出できず。
ping
を打った結果、宛先が間違っているのか戻りがないのか判別できませんでした。
(なので、ping
をlocal
の192.168.1.1
~192.168.1.254
へ順次打って反応を見るのも駄目でした…)
ARPを使う
ping
を個々のマシンに打ってみると、返答はなかったけれど結果としてARP
テーブルが更新されていました。
ping
を打つときにARP
が行われていて、MAC
アドレスの取得には成功している様子だったので、そちらを使うことに。
(自分の理解では、ping
を打つときにはICMP
というプロトコルで通信が行われていて、その前にMAC
アドレスを調べるためにARP
プロトコルで通信が行われていて、localマシンのARP
テーブルが更新されている、という理解ですが、間違っているかもしれません…)
流れ
- 自分PCの
ネットワークインタフェース
を列挙、IPv4
アドレスが付与されていればそれを記録 - 自分PCアドレスから
IP
のネットワーク部をsplit
して、全ホストへARP
送信(IPv6
はARP
とはべつのプロトコル
らしいのでこれでIPv4
を取得) MAC
アドレスが取得できればIP
が生きていると判断- 最後に
ViewModel
側で自分のIP
とLAN
内のすべてのIP
を突合してバインド
自分PCが複数IP
でもちゃんと表示される、はず…
それからネットワーク部を自分PCから判定しているので、192.168.0.~
でも192.168.1.~
いい感じに検出できるはずです…
ネットワークフェースの列挙
LANIPSearcher/LANSearch.xaml.cs
private void SetSelfLocalIP() { // WiFi,LANアダプタ等のインタフェースをすべて取得 NetworkInterface[] nis = NetworkInterface.GetAllNetworkInterfaces(); foreach (var interfaces in nis) { // 接続できて、ループバックインタフェース、トンネルインタフェースを除く if (interfaces.OperationalStatus == OperationalStatus.Up && interfaces.NetworkInterfaceType != NetworkInterfaceType.Loopback && interfaces.NetworkInterfaceType != NetworkInterfaceType.Tunnel) { // インタフェースの中からさらにIPを見ていく UnicastIPAddressInformationCollection unicastIPs = interfaces.GetIPProperties().UnicastAddresses; foreach (var ip in unicastIPs) { // このPCのIPv4を登録 if (ip.Address.AddressFamily == AddressFamily.InterNetwork) { IPBean.AddSelfIP(Convert.ToString(ip.Address)); } } } } }
ARP送信
LANIPSearcher/LANSearch.xaml.cs
private void SendARP() { // デフォルトだとスレッド起動に時間がかかるため int workThreadsMin; int ioThreadsMin; ThreadPool.GetMinThreads(out workThreadsMin, out ioThreadsMin); ThreadPool.SetMinThreads(260, ioThreadsMin); // 1~254のホストへARP送信 List<Task> allTasks = new List<Task>(); for (int i = 1; i <= 254; i++) { int hostPart = i; allTasks.Add(Task.Run(() => { // IPからネットワーク部を取得 List<string> separateIP = this.IPBean.SelfIPList[0].Split('.').ToList(); separateIP.RemoveAt(3); string networkPart = string.Join(".", separateIP); // ネットワーク部 + ホスト部でLocalIPへARPを投げる string destinationIP = networkPart + "." + hostPart; int destinationIPBytes = BitConverter.ToInt32(IPAddress.Parse(destinationIP).GetAddressBytes(), 0); byte[] macAddressPointer = new byte[6]; int physicalAddressLength = macAddressPointer.Length; // ARP int ret = SendARP(destinationIPBytes, 0, macAddressPointer, ref physicalAddressLength); if (ret == 0) { this.IPBean.AddLANIP(destinationIP); } } )); } Task t = Task.WhenAll(allTasks); try { t.Wait(); } catch { MessageBox.Show("エラー終了"); } }
ViewModel
LANIPSearcher/Bean/LANSearchBean.cs
private List<string> _selfIPList; private List<string> _allLANIPList; public string ShowText { get { // ローカルマシンのIPリストと突合 this.SelfIPList.ForEach( x => { int index = this._allLANIPList.IndexOf(x); if (index > -1) { this._allLANIPList.RemoveAt(index); this._allLANIPList.Insert(index, x + " (this PC)"); } }); return string.Join(Environment.NewLine, this._allLANIPList); } }
参考
ネットワークインターフェイスの構成、統計情報を取得する - .NET Tips (VB.NET,C#...)
ローカルマシンのIPv4アドレスを取得する | 手帳.net
ネットワークへの接続状態を取得する - bnote
ARPの動作 - ネットワークエンジニアを目指して
LAN接続IP一覧(C#/VB.NET) [サンプルソース] [ヨーキー景吾の逃走]
[C#] ARP要求を送信してリモートPCのMACアドレスを取得する(SendARP関数) – 行け!偏差値40プログラマー
ARPテーブルの取得 (C#)(F#) - SIN@SAPPOROWORKSの覚書
Windowsで、使用中のIPアドレスを調査する:Tech TIPS - @IT
LAN内で使用中のIPアドレス(pingで応答があるノード)を簡易に調査するワンライナー(Windows編) - 元RX-7乗りの適当な日々