You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

457 lines
15 KiB

  1. using Apewer.Internals.Interop;
  2. using Apewer.Network;
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.Globalization;
  7. using System.Net;
  8. using System.Net.NetworkInformation;
  9. using System.Net.Sockets;
  10. using System.Runtime.InteropServices;
  11. using System.Text;
  12. namespace Apewer
  13. {
  14. /// <summary></summary>
  15. public class NetworkUtility
  16. {
  17. #region UDP
  18. /// <summary>唤醒局域网中拥有指定 MAC 地址的设备。</summary>
  19. /// <param name="mac">被唤醒设备的 MAC 地址,必须是长度为 6 的字节数组。</param>
  20. public static void WakeOnLan(byte[] mac)
  21. {
  22. if (mac.Length != 6) return;
  23. var uc = new System.Net.Sockets.UdpClient();
  24. uc.Connect(IPAddress.Broadcast, 65535);
  25. var pack = new List<byte>();
  26. // 前 6 字节为 0xFF。
  27. for (int i = 0; i < 6; i++) pack.Add(255);
  28. // 目标 MAC 地址重复 16 次。
  29. for (int i = 0; i < 16; i++)
  30. {
  31. for (int j = 0; j < 6; j++) pack.Add(mac[j]);
  32. }
  33. // 发送 102 字节数据。
  34. uc.Send(pack.ToArray(), pack.Count);
  35. uc.Close();
  36. }
  37. /// <summary>从 NTP 服务器获取 UTC 时间。</summary>
  38. /// <remarks>
  39. /// Worldwide: pool.ntp.org<br/>
  40. /// Asia: asia.pool.ntp.org<br/>
  41. /// Europe: europe.pool.ntp.org<br/>
  42. /// North: America north-america.pool.ntp.org<br/>
  43. /// Oceania: oceania.pool.ntp.org<br/>
  44. /// South America: south-america.pool.ntp.org<br/>
  45. /// Windows: time.windows.com<br/>
  46. /// Windows: time.nist.gov<br/>
  47. /// China: us.ntp.org.cn<br/>
  48. /// China: edu.ntp.org.cn<br/>
  49. /// </remarks>
  50. public static DateTime GetUtcFromNtp(string server = "pool.ntp.org", int port = 123, int timeout = 1000)
  51. {
  52. try
  53. {
  54. var addresses = Dns.GetHostEntry(server).AddressList;
  55. if (addresses.Length > 0)
  56. {
  57. var endpoint = new IPEndPoint(addresses[0], port);
  58. return GetUtcFromNtp(endpoint, timeout);
  59. }
  60. }
  61. catch (Exception ex)
  62. {
  63. }
  64. return ClockUtility.Zero;
  65. }
  66. /// <summary>从 NTP 服务器获取 UTC 时间。</summary>
  67. public static DateTime GetUtcFromNtp(IPEndPoint endpoint, int timeout = 1000)
  68. {
  69. try
  70. {
  71. var request = new byte[48];
  72. request[0] = 0x1B;
  73. var response = new byte[48];
  74. response[0] = 0x1B;
  75. var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  76. socket.Connect(endpoint);
  77. socket.ReceiveTimeout = timeout;
  78. socket.Send(request);
  79. socket.Receive(response);
  80. socket.Close();
  81. const byte replytime = 40;
  82. ulong secondspart = BitConverter.ToUInt32(response, replytime);
  83. ulong secondsfraction = BitConverter.ToUInt32(response, replytime + 4);
  84. secondspart = SwapEndian(secondspart);
  85. secondsfraction = SwapEndian(secondsfraction);
  86. ulong milliseconds = (secondspart * 1000) + ((secondsfraction * 1000) / 0x100000000UL);
  87. var utc = (new DateTime(1900, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds(milliseconds);
  88. return utc;
  89. }
  90. catch (Exception ex)
  91. {
  92. }
  93. return ClockUtility.Zero;
  94. }
  95. private static uint SwapEndian(ulong x)
  96. {
  97. var a = ((x & 0x000000ff) << 24);
  98. var b = ((x & 0x0000ff00) << 8);
  99. var c = ((x & 0x00ff0000) >> 8);
  100. var d = ((x & 0xff000000) >> 24);
  101. return (uint)(a + b + c + d);
  102. }
  103. #endregion
  104. #region ARP
  105. #if NET40 || NET461
  106. /// <summary>发送 ARP 请求,获取目标 IP 地址对应设备的 MAC 地址,MAC 格式为 01-23-45-67-89-AB。</summary>
  107. /// <param name="ip">目标 IP 地址。</param>
  108. /// <returns>MAC 地址。</returns>
  109. public static string SendARP(string ip)
  110. {
  111. if (!string.IsNullOrEmpty(ip))
  112. {
  113. try
  114. {
  115. var ipa = IPAddress.Parse(ip);
  116. uint dip = BitConverter.ToUInt32(ipa.GetAddressBytes(), 0);
  117. ulong mac = 0;
  118. uint len = 6;
  119. uint err = IpHlpApi.SendARP(dip, 0, ref mac, ref len);
  120. byte[] bytes = BitConverter.GetBytes(mac);
  121. return BitConverter.ToString(bytes, 0, 6);
  122. }
  123. catch { }
  124. }
  125. return "";
  126. }
  127. #endif
  128. #endregion
  129. #region Puny Code
  130. /// <summary></summary>
  131. public static string ToPunyCode(string chinese)
  132. {
  133. if (string.IsNullOrEmpty(chinese)) return "";
  134. try { return new IdnMapping().GetAscii(chinese); }
  135. catch { return chinese; }
  136. }
  137. /// <summary></summary>
  138. public static string FromPunyCode(string punycode)
  139. {
  140. if (string.IsNullOrEmpty(punycode)) return "";
  141. try { return new IdnMapping().GetUnicode(punycode); }
  142. catch { return punycode; }
  143. }
  144. #endregion
  145. #region IP
  146. /// <summary>获取本地计算机的计算机名。</summary>
  147. public static string LocalHost
  148. {
  149. get
  150. {
  151. var hn = Dns.GetHostName();
  152. return string.IsNullOrEmpty(hn) ? "" : hn;
  153. }
  154. }
  155. /// <summary>本地计算机的 IP 地址。</summary>
  156. public static List<string> LocalIP
  157. {
  158. get
  159. {
  160. var list = new List<string>();
  161. var he = Dns.GetHostEntry(Dns.GetHostName());
  162. foreach (var ip in he.AddressList)
  163. {
  164. list.Add(ip.ToString());
  165. }
  166. return list;
  167. }
  168. }
  169. /// <summary>判断 IPv4 地址格式是否正确。</summary>
  170. public static bool IsIP(string ipv4)
  171. {
  172. try
  173. {
  174. if (string.IsNullOrEmpty(ipv4)) return false;
  175. var split = ipv4.Split('.');
  176. if (split.Length != 4) return false;
  177. for (int i = 0; i < 4; i++)
  178. {
  179. var n = Convert.ToInt32(split[i]);
  180. if (n < 0 || n > 255) return false;
  181. if (n.ToString() != split[i]) return false;
  182. }
  183. return true;
  184. }
  185. catch { }
  186. return false;
  187. }
  188. /// <summary>对目标地址进行解析。</summary>
  189. public static string Resolve(string host)
  190. {
  191. try
  192. {
  193. if (IsIP(host))
  194. {
  195. var ip = IPAddress.Parse(host);
  196. var he = Dns.GetHostEntry(ip);
  197. return he.HostName;
  198. }
  199. else
  200. {
  201. var ip = "";
  202. var dn = host.ToLower();
  203. var he = Dns.GetHostEntry(dn);
  204. var ts = "";
  205. var on = he.Aliases;
  206. he = Dns.GetHostEntry(dn);
  207. for (int i = 0; i < on.Length; i++) ts = ts + on[i].ToString() + ",";
  208. ts = "";
  209. var al = he.AddressList;
  210. for (int i = 0; i < al.Length; i++) ts = ts + al[i].ToString() + ",";
  211. ip = ts;
  212. if (ip.Length > 0)
  213. {
  214. if (ip.Substring(ip.Length - 1, 1) == ",") ip = ip.Substring(0, ip.Length - 1);
  215. }
  216. return ip;
  217. }
  218. }
  219. catch { }
  220. return "";
  221. }
  222. /// <summary>对目标地址进行解析。</summary>
  223. private static IPHostEntry InternalResolve(string hostName)
  224. {
  225. if (hostName.Length <= 255 && (hostName.Length != 255 || hostName[254] == '.'))
  226. {
  227. var intPtr = WS2_32.gethostbyname(hostName);
  228. if (intPtr != IntPtr.Zero) return NativeToHostEntry(intPtr);
  229. }
  230. return null;
  231. }
  232. private static IntPtr IntPtrAdd(IntPtr a, int b)
  233. {
  234. return (IntPtr)((long)a + b);
  235. }
  236. private static IPHostEntry NativeToHostEntry(IntPtr nativePointer)
  237. {
  238. hostent hostent = (hostent)Marshal.PtrToStructure(nativePointer, typeof(hostent));
  239. IPHostEntry iPHostEntry = new IPHostEntry();
  240. if (hostent.h_name != IntPtr.Zero)
  241. {
  242. iPHostEntry.HostName = Marshal.PtrToStringAnsi(hostent.h_name);
  243. }
  244. ArrayList arrayList = new ArrayList();
  245. IntPtr intPtr = hostent.h_addr_list;
  246. nativePointer = Marshal.ReadIntPtr(intPtr);
  247. while (nativePointer != IntPtr.Zero)
  248. {
  249. int newAddress = Marshal.ReadInt32(nativePointer);
  250. arrayList.Add(new IPAddress(newAddress));
  251. intPtr = IntPtrAdd(intPtr, IntPtr.Size);
  252. nativePointer = Marshal.ReadIntPtr(intPtr);
  253. }
  254. iPHostEntry.AddressList = new IPAddress[arrayList.Count];
  255. arrayList.CopyTo(iPHostEntry.AddressList, 0);
  256. arrayList.Clear();
  257. intPtr = hostent.h_aliases;
  258. nativePointer = Marshal.ReadIntPtr(intPtr);
  259. while (nativePointer != IntPtr.Zero)
  260. {
  261. string value = Marshal.PtrToStringAnsi(nativePointer);
  262. arrayList.Add(value);
  263. intPtr = IntPtrAdd(intPtr, IntPtr.Size);
  264. nativePointer = Marshal.ReadIntPtr(intPtr);
  265. }
  266. iPHostEntry.Aliases = new string[arrayList.Count];
  267. arrayList.CopyTo(iPHostEntry.Aliases, 0);
  268. return iPHostEntry;
  269. }
  270. /// <summary>将由字符串表示的 IPv4 地址转换为 32 位整数。</summary>
  271. public static int GetNumber(IPAddress ipv4)
  272. {
  273. try
  274. {
  275. var ba = ipv4.GetAddressBytes();
  276. return BitConverter.ToInt32(ba, 0);
  277. }
  278. catch { return 0; }
  279. }
  280. /// <summary>转换 IP 地址格式。</summary>
  281. public static string GetPlainAddress(IPAddress address)
  282. {
  283. try { return address.ToString(); }
  284. catch { return ""; }
  285. }
  286. /// <summary>转换 IP 地址格式。</summary>
  287. public static string GetPlainAddress(IPEndPoint endpoint)
  288. {
  289. try { return GetPlainAddress(endpoint.Address); }
  290. catch { return ""; }
  291. }
  292. /// <summary>转换 IP 地址格式。</summary>
  293. public static IPAddress GetIPAddress(string address)
  294. {
  295. try { return IPAddress.Parse(address); }
  296. catch { return new IPAddress(0); }
  297. }
  298. /// <summary>转换 IP 地址格式。</summary>
  299. public static IPEndPoint GetIPEndPoint(string address, int port)
  300. {
  301. try { return new IPEndPoint(IPAddress.Parse(address), NumberUtility.RestrictValue(port, 0, ushort.MaxValue)); }
  302. catch { return new IPEndPoint(0, 0); }
  303. }
  304. /// <summary>转换 IP 地址格式。</summary>
  305. public static IPEndPoint GetIPEndPoint(IPAddress address, int port)
  306. {
  307. try { return new IPEndPoint(address, NumberUtility.RestrictValue(port, 0, ushort.MaxValue)); }
  308. catch { return new IPEndPoint(0, 0); }
  309. }
  310. /// <summary>转换 IP 地址格式。</summary>
  311. public static IPEndPoint GetIPEndPoint(EndPoint endpoint)
  312. {
  313. try { return (IPEndPoint)endpoint; }
  314. catch { return new IPEndPoint(0, 0); }
  315. }
  316. /// <summary>判断私有 IP 地址。</summary>
  317. public static bool FromLAN(string ipv4)
  318. {
  319. if (ipv4.IsEmpty()) return false;
  320. // localhost
  321. if (ipv4 == "::1") return true;
  322. if (ipv4 == "127.0.0.1") return true;
  323. // IPv4
  324. var a = ipv4.Split('.');
  325. if (a.Length != 4) return false;
  326. switch (a[0])
  327. {
  328. case "10":
  329. return true;
  330. case "172":
  331. var a1 = TextUtility.GetInt32(a[1]);
  332. if (a1 >= 16 && a1 <= 31) return true;
  333. break;
  334. case "192":
  335. if (a[1] == "168") return true;
  336. break;
  337. }
  338. return false;
  339. }
  340. #endregion
  341. #region HTTP
  342. /// <summary>GET</summary>
  343. public static HttpClient HttpGet(string url, int timeout = 30000)
  344. {
  345. return HttpClient.SimpleGet(url, timeout);
  346. }
  347. /// <summary>POST</summary>
  348. public static HttpClient HttpPost(string url, byte[] data, int timeout = 30000, string type = "application/octet-stream")
  349. {
  350. return HttpClient.SimplePost(url, data, timeout, type);
  351. }
  352. /// <summary>POST text/plain</summary>
  353. public static HttpClient HttpPost(string url, string text, int timeout = 30000, string type = "text/plain")
  354. {
  355. return HttpClient.SimpleText(url, text, timeout, type);
  356. }
  357. /// <summary>POST application/x-www-form-urlencoded</summary>
  358. public static HttpClient HttpPost(string url, IDictionary<string, string> form, int timeout = 30000)
  359. {
  360. return HttpClient.SimpleForm(url, form, timeout);
  361. }
  362. /// <summary>POST application/x-www-form-urlencoded</summary>
  363. public static HttpClient HttpPost(string url, TextSet form, int timeout = 30000)
  364. {
  365. return HttpClient.SimpleForm(url, form, timeout);
  366. }
  367. #endregion
  368. #region Port
  369. private static List<int> ListActivePort(IPEndPoint[] endpoints)
  370. {
  371. var list = new List<int>(endpoints.Length);
  372. foreach (var endpoint in endpoints)
  373. {
  374. var port = endpoint.Port;
  375. if (list.Contains(port)) continue;
  376. list.Add(port);
  377. }
  378. list.Sort();
  379. list.Capacity = list.Count;
  380. return list;
  381. }
  382. /// <summary>列出活动的 TCP 端口。</summary>
  383. public static List<int> ListActiveTcpPort()
  384. {
  385. return ListActivePort(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
  386. }
  387. /// <summary>列出活动的 UDP 端口。</summary>
  388. public static List<int> ListActiveUdpPort()
  389. {
  390. return ListActivePort(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
  391. }
  392. #endregion
  393. }
  394. }