first commit

This commit is contained in:
DevRas 2022-09-04 08:35:19 +09:00
commit 69ce69b771
11 changed files with 619 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
bin
obj

36
DeviceInfo.cs Normal file
View File

@ -0,0 +1,36 @@
using System.Net;
using System.Text;
namespace NWService
{
public class DeviceInfo
{
private IPAddress ipAddr;
private byte[] macAddr;
public DeviceInfo(IPAddress iPAddress, byte[] macAddressBytes)
{
this.ipAddr = iPAddress;
this.macAddr = macAddressBytes;
}
public IPAddress GetIPAddress()
{
return ipAddr;
}
public string GetMacAddress(char separate = ':')
{
StringBuilder sb = new StringBuilder(18);
foreach (byte b in this.macAddr) {
if (sb.Length > 0)
{
sb.Append(separate);
}
sb.Append(string.Format("{0:X2}", b));
}
return sb.ToString();
}
}
}

104
DicSerialize.cs Normal file
View File

@ -0,0 +1,104 @@
using System.Xml.Serialization;
using System.Text;
using System.Text.Encodings;
namespace NWService
{
public class DicSerialize
{
/// <summary>
/// シリアル化できる、KeyValuePairに代わる構造体
/// </summary>
/// <typeparam name="TKey">Keyの型</typeparam>
/// <typeparam name="TValue">Valueの型</typeparam>
[Serializable]
public struct KeyAndValue<TKey, TValue>
{
public TKey Key;
public TValue Value;
public KeyAndValue(KeyValuePair<TKey, TValue> pair)
{
Key = pair.Key;
Value = pair.Value;
}
}
/// <summary>
/// DictionaryをKeyAndValueのListに変換する
/// </summary>
/// <typeparam name="TKey">Dictionaryのキーの型</typeparam>
/// <typeparam name="TValue">Dictionaryの値の型</typeparam>
/// <param name="dic">変換するDictionary</param>
/// <returns>変換されたKeyAndValueのList</returns>
public static List<KeyAndValue<TKey, TValue>> ConvertDictionaryToList<TKey, TValue>(Dictionary<TKey, TValue> dic)
{
List<KeyAndValue<TKey, TValue>> lst = new List<KeyAndValue<TKey, TValue>>();
foreach (KeyValuePair<TKey, TValue> pair in dic)
{
lst.Add(new KeyAndValue<TKey, TValue>(pair));
}
return lst;
}
/// <summary>
/// KeyAndValueのListをDictionaryに変換する
/// </summary>
/// <typeparam name="TKey">KeyAndValueのKeyの型</typeparam>
/// <typeparam name="TValue">KeyAndValueのValueの型</typeparam>
/// <param name="lst">変換するKeyAndValueのList</param>
/// <returns>変換されたDictionary</returns>
public static Dictionary<TKey, TValue> ConvertListToDictionary<TKey, TValue>(List<KeyAndValue<TKey, TValue>> lst)
{
Dictionary<TKey, TValue> dic = new Dictionary<TKey, TValue>();
foreach (KeyAndValue<TKey, TValue> pair in lst)
{
dic.Add(pair.Key, pair.Value);
}
return dic;
}
/// <summary>
/// DictionaryをXMLファイルに保存する
/// </summary>
/// <typeparam name="TKey">Dictionaryのキーの型</typeparam>
/// <typeparam name="TValue">Dictionaryの値の型</typeparam>
/// <param name="fileName">保存先のXMLファイル名</param>
/// <param name="dic">保存するDictionary</param>
public static void XmlSerialize<TKey, TValue>(string fileName, Dictionary<TKey, TValue> dic)
{
//シリアル化できる型に変換
List<KeyAndValue<TKey, TValue>> obj = ConvertDictionaryToList(dic);
//XMLファイルに保存
XmlSerializer serializer = new XmlSerializer(typeof(List<KeyAndValue<TKey, TValue>>));
StreamWriter sw =
new StreamWriter(fileName, false, new UTF8Encoding(false));
serializer.Serialize(sw, obj);
sw.Close();
}
/// <summary>
/// シリアル化されたXMLファイルをDictionaryに復元する
/// </summary>
/// <typeparam name="TKey">Dictionaryのキーの型</typeparam>
/// <typeparam name="TValue">Dictionaryの値の型</typeparam>
/// <param name="fileName">復元するXMLファイル名</param>
/// <returns>復元されたDictionary</returns>
public static Dictionary<TKey, TValue> XmlDeserialize<TKey, TValue>(
string fileName)
{
//XMLファイルから復元
XmlSerializer serializer = new XmlSerializer(typeof(List<KeyAndValue<TKey, TValue>>));
StreamReader sr = new StreamReader(fileName, new UTF8Encoding(false));
List<KeyAndValue<TKey, TValue>> obj =
(List<KeyAndValue<TKey, TValue>>)serializer.Deserialize(sr);
sr.Close();
//Dictionaryに戻す
Dictionary<TKey, TValue> dic = ConvertListToDictionary(obj);
return dic;
}
}
}

25
LanguageXml.cs Normal file
View File

@ -0,0 +1,25 @@
using System.Collections.Generic;
namespace NWService
{
public class LanguageXml
{
public LanguageXml()
{
this.messageMaps = new Dictionary<string, string>();
}
public Dictionary<string, string> messageMaps = new Dictionary<string, string>();
public string GetMessage(string key, string defaultMessage)
{
if (messageMaps.ContainsKey(key))
{
return messageMaps[key];
}
else
{
return defaultMessage;
}
}
}
}

47
LanguageXmlLoader.cs Normal file
View File

@ -0,0 +1,47 @@
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace NWService
{
public class LanguageXmlLoader
{
public static string GetPath()
{
return Path.Combine(Directory.GetCurrentDirectory(), "language.xml");
}
public static LanguageXml Load()
{
if (!File.Exists(GetPath()))
{
return default;
}
try
{
Dictionary<string, string> dic = DicSerialize.XmlDeserialize<string, string>(GetPath());
return new LanguageXml()
{
messageMaps = dic
};
}
catch(Exception e)
{
Console.WriteLine(e);
return default;
}
}
public static void Save(LanguageXml xml)
{
try
{
DicSerialize.XmlSerialize<string, string>(GetPath(), xml.messageMaps);
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
}
}

131
NetworkService.cs Normal file
View File

@ -0,0 +1,131 @@
using System.Net;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
namespace NWService
{
public class NetworkService
{
[DllImport("iphlpapi.dll", ExactSpelling = true)]
private static extern int SendARP(int dstIp, int srcIp, byte[] mac, ref int macLen);
public static PingReply Ping(IPAddress iPAddress)
{
using (Ping ping = new Ping())
{
PingReply reply = ping.Send(iPAddress);
return reply;
}
}
public static List<PingReply> SearchByPing(IPAddress targetIPv4)
{
int workThreadsMin;
int ioThreadsMin;
ThreadPool.GetMinThreads(out workThreadsMin, out ioThreadsMin);
ThreadPool.SetMinThreads(260, ioThreadsMin);
List<PingReply> avaIPs = new List<PingReply>();
List<Task> allTasks = new List<Task>();
for (int i = 1 ; i <= 254 ; i++)
{
int hostPart = i;
allTasks.Add(Task.Run(() => {
List<string> separateIP = targetIPv4.ToString().Split('.').ToList();
separateIP.RemoveAt(3);
separateIP.Add(hostPart.ToString());
string networkPart = string.Join(".", separateIP);
PingReply reply = Ping(IPAddress.Parse(networkPart));
if (reply != null && reply.Status == IPStatus.Success)
{
avaIPs.Add(reply);
}
}));
}
Task t = Task.WhenAll(allTasks);
try
{
t.Wait();
}
catch(Exception error)
{
Console.WriteLine(error);
}
return avaIPs;
}
public static List<DeviceInfo> SearchARP(IPAddress targetIPv4)
{
int workThreadsMin;
int ioThreadsMin;
ThreadPool.GetMinThreads(out workThreadsMin, out ioThreadsMin);
ThreadPool.SetMinThreads(260, ioThreadsMin);
List<DeviceInfo> avaIPs = new List<DeviceInfo>();
List<Task> allTasks = new List<Task>();
for (int i = 1 ; i <= 254; i++)
{
int hostPart = i;
allTasks.Add(Task.Run(() => {
List<string> separateIP = targetIPv4.ToString().Split('.').ToList();
separateIP.RemoveAt(3);
separateIP.Add(hostPart.ToString());
string networkPart = string.Join(".", separateIP);
int IPBytes = BitConverter.ToInt32(IPAddress.Parse(networkPart).GetAddressBytes(), 0);
byte[] macAddressPointer = new byte[6];
int physicalAddressLength = macAddressPointer.Length;
// ARP
int ret = SendARP(IPBytes, 0, macAddressPointer, ref physicalAddressLength);
if (ret == 0)
{
DeviceInfo info = new DeviceInfo(IPAddress.Parse(networkPart), macAddressPointer);
avaIPs.Add(info);
}
}));
}
Task t = Task.WhenAll(allTasks);
try
{
t.Wait();
}
catch(Exception error)
{
Console.WriteLine(error);
}
return avaIPs;
}
public static IEnumerable<IPAddress> GetLocalIPv4()
{
List<IPAddress> list = new List<IPAddress>();
NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface nic in nics)
{
if (nic.OperationalStatus == OperationalStatus.Up
&& nic.NetworkInterfaceType != NetworkInterfaceType.Loopback
&& nic.NetworkInterfaceType != NetworkInterfaceType.Tunnel)
{
UnicastIPAddressInformationCollection unicast = nic.GetIPProperties().UnicastAddresses;
foreach (UnicastIPAddressInformation ip in unicast)
{
if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
list.Add(ip.Address);
}
}
}
}
return list;
}
}
}

10
NetworkService.csproj Normal file
View File

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
</PropertyGroup>
</Project>

74
OptionConsole.cs Normal file
View File

@ -0,0 +1,74 @@
using System.Net;
namespace NWService
{
public class OptionConsole
{
public static ServiceMode GetServiceMode(LanguageXml language)
{
var arry = Enum.GetValues(typeof(ServiceMode));
for (int i = 0 ; i < arry.Length ; i++)
{
Console.WriteLine("[{0}]: {1}", i, language.GetMessage(arry.GetValue(i).ToString(), arry.GetValue(i).ToString()));
}
Console.Write("{0} ", language.GetMessage("select_service_mode", "Please type service mode:"));
string tInput = Console.ReadLine();
if (string.IsNullOrWhiteSpace(tInput) || !int.TryParse(tInput, out int mode))
{
throw new ArgumentException(string.Format("{0}", language.GetMessage("exception_invalid_input_mode", "invalid input mode.")));
}
if (mode < 0 || mode > arry.Length)
{
throw new ArgumentException(string.Format("{0}", language.GetMessage("exception_invalid_input_mode", "invalid input mode.")));
}
return (ServiceMode) mode;
}
public static IPAddress GetIPAddress(List<IPAddress> localIPv4, LanguageXml language)
{
for (int i = 0 ; i < localIPv4.Count(); i++)
{
Console.WriteLine("#{0}: {1}", i + 1, localIPv4[i]);
}
Console.WriteLine("[0]: {0}", language.GetMessage("select_target_ipaddr", "Type target IPAddress."));
Console.WriteLine("[1-]: {0}", language.GetMessage("select_local_ipaddr", "Select local IPAddress."));
Console.Write("{0} ", language.GetMessage("type_mode", "Please type select mode:"));
string tMode = Console.ReadLine();
if (string.IsNullOrWhiteSpace(tMode))
{
throw new ArgumentException(string.Format("{0}", language.GetMessage("exception_invalid_input_mode", "invalid input mode.")));
}
if (!int.TryParse(tMode, out int mode))
{
throw new ArgumentException(string.Format("{0}", language.GetMessage("exception_invalid_input_mode", "invalid input mode.")));
}
if (mode == 0)
{
Console.Write("{0} ", language.GetMessage("type_target_ipaddr", "Please type target IPAddress:"));
string tmpAddr = Console.ReadLine();
if (!IPAddress.TryParse(tmpAddr, out IPAddress addr))
{
throw new ArgumentException(string.Format("{0}", language.GetMessage("exception_invalid_input_ipaddr", "invalid input IPAddress.")));
}
return addr;
}
mode = mode - 1;
if (mode < 0 || mode > localIPv4.Count())
{
throw new ArgumentException(string.Format("{0}", language.GetMessage("exception_invalid_input_mode", "invalid input mode.")));
}
return localIPv4[mode];
}
}
}

135
Program.cs Normal file
View File

@ -0,0 +1,135 @@
using System.Net;
using System.Net.NetworkInformation;
namespace NWService
{
public class Program
{
public static void Main()
{
try
{
LanguageXml language = LanguageXmlLoader.Load();
ServiceMode mode = OptionConsole.GetServiceMode(language);
List<IPAddress> localIPv4 = NetworkService.GetLocalIPv4().ToList();
IPAddress targetIPv4 = OptionConsole.GetIPAddress(localIPv4, language);
switch(mode)
{
case ServiceMode.SEARCH_ARP:
Search_ARP(targetIPv4, language);
break;
case ServiceMode.SEARCH_PING:
Search_Ping(targetIPv4, language);
break;
default:
Console.WriteLine("unknown mode...");
break;
}
}
catch(Exception error)
{
Console.WriteLine(error.Message);
}
}
public static void Search_ARP(IPAddress targetIPv4, LanguageXml language)
{
try
{
List<DeviceInfo> findList = new List<DeviceInfo>();
Task task = Task.Run(() => {
findList.AddRange(NetworkService.SearchARP(targetIPv4));
Thread.Sleep(10);
});
string[] frames = {"","",""};
int frameCount = 0;
(int cpL, int cpT) = Console.GetCursorPosition();
while (!task.IsCompleted)
{
Console.SetCursorPosition(cpL, cpT);
frameCount++;
int targetFrameNumber = frameCount%frames.Length;
Console.WriteLine("{0} {1}", frames[targetFrameNumber], language.GetMessage("searching", "searching..."));
Thread.Sleep(100);
}
Console.SetCursorPosition(cpL, cpT);
Console.WriteLine(" ");
if (findList.Count() == 0)
{
Console.WriteLine("{0}", language.GetMessage("empty_find_list", "Not found..."));
}
else
{
Console.WriteLine(string.Format(language.GetMessage("found_devices","Found {0} Devices."), findList.Count()));
foreach (DeviceInfo deviceInfo in findList)
{
Console.WriteLine("――――――――――――――――――――――――――――");
Console.WriteLine("IP: {0}", deviceInfo.GetIPAddress().ToString());
Console.WriteLine("Mac: {0}", deviceInfo.GetMacAddress());
}
}
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
public static void Search_Ping(IPAddress targetIPv4, LanguageXml language)
{
try
{
List<PingReply> findList = new List<PingReply>();
Task task = Task.Run(() => {
findList.AddRange(NetworkService.SearchByPing(targetIPv4));
Thread.Sleep(10);
});
string[] frames = {"","",""};
int frameCount = 0;
(int cpL, int cpT) = Console.GetCursorPosition();
while (!task.IsCompleted)
{
Console.SetCursorPosition(cpL, cpT);
frameCount++;
int targetFrameNumber = frameCount%frames.Length;
Console.WriteLine("{0} {1}", frames[targetFrameNumber], language.GetMessage("searching", "searching..."));
Thread.Sleep(100);
}
Console.SetCursorPosition(cpL, cpT);
Console.WriteLine(" ");
if (findList.Count() == 0)
{
Console.WriteLine("{0}", language.GetMessage("empty_find_list", "Not found..."));
}
else
{
Console.WriteLine(string.Format(language.GetMessage("found_devices","Found {0} Devices."), findList.Count()));
foreach (var reply in findList)
{
Console.WriteLine("――――――――――――――――――――――――――――");
Console.WriteLine("IP: {0}", reply.Address.ToString());
Console.WriteLine("Time: {0}ms", reply.RoundtripTime);
Console.WriteLine("Status: {0}", reply.Status);
Console.WriteLine("Ttl: {0}", reply.Options.Ttl);
}
}
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
}
}

8
ServiceMode.cs Normal file
View File

@ -0,0 +1,8 @@
namespace NWService
{
public enum ServiceMode
{
SEARCH_ARP,
SEARCH_PING,
}
}

47
language.xml Normal file
View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfKeyAndValueOfStringString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<KeyAndValueOfStringString>
<Key>SEARCH_ARP</Key>
<Value>検索 [ARP]</Value>
</KeyAndValueOfStringString>
<KeyAndValueOfStringString>
<Key>SEARCH_PING</Key>
<Value>検索 [PING]</Value>
</KeyAndValueOfStringString>
<KeyAndValueOfStringString>
<Key>searching</Key>
<Value>検索中</Value>
</KeyAndValueOfStringString>
<KeyAndValueOfStringString>
<Key>empty_find_list</Key>
<Value>IPアドレスが見つかりませんでした。</Value>
</KeyAndValueOfStringString>
<KeyAndValueOfStringString>
<Key>select_target_ipaddr</Key>
<Value>対象のIPアドレスを入力する</Value>
</KeyAndValueOfStringString>
<KeyAndValueOfStringString>
<Key>select_local_ipaddr</Key>
<Value>ローカルIPアドレスから選択する</Value>
</KeyAndValueOfStringString>
<KeyAndValueOfStringString>
<Key>type_target_ipaddr</Key>
<Value>対象のIPアドレスを入力してください</Value>
</KeyAndValueOfStringString>
<KeyAndValueOfStringString>
<Key>type_mode</Key>
<Value>モードを入力してください:</Value>
</KeyAndValueOfStringString>
<KeyAndValueOfStringString>
<Key>exception_invalid_input_mode</Key>
<Value>入力されたモードが正しくありません。</Value>
</KeyAndValueOfStringString>
<KeyAndValueOfStringString>
<Key>exception_invalid_input_ipaddr</Key>
<Value>入力されたIPアドレスが正しくありません。</Value>
</KeyAndValueOfStringString>
<KeyAndValueOfStringString>
<Key>version</Key>
<Value>1.0.0</Value>
</KeyAndValueOfStringString>
</ArrayOfKeyAndValueOfStringString>