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.

411 lines
14 KiB

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