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.

358 lines
11 KiB

  1. using Apewer;
  2. using Apewer.Internals.Interop;
  3. using Apewer.Network;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Globalization;
  7. using System.Net;
  8. using System.Net.Sockets;
  9. using System.Text;
  10. namespace Apewer
  11. {
  12. /// <summary></summary>
  13. public class NetworkUtility
  14. {
  15. #region UDP
  16. /// <summary>唤醒局域网中拥有指定 MAC 地址的设备。</summary>
  17. /// <param name="mac">被唤醒设备的 MAC 地址,必须是长度为 6 的字节数组。</param>
  18. public static void WakeOnLan(byte[] mac)
  19. {
  20. if (mac.Length != 6) return;
  21. var uc = new System.Net.Sockets.UdpClient();
  22. uc.Connect(IPAddress.Broadcast, 65535);
  23. var pack = new List<byte>();
  24. // 前 6 字节为 0xFF。
  25. for (int i = 0; i < 6; i++) pack.Add(255);
  26. // 目标 MAC 地址重复 16 次。
  27. for (int i = 0; i < 16; i++)
  28. {
  29. for (int j = 0; j < 6; j++) pack.Add(mac[j]);
  30. }
  31. // 发送 102 字节数据。
  32. uc.Send(pack.ToArray(), pack.Count);
  33. uc.Close();
  34. }
  35. /// <summary>从 NTP 服务器获取 UTC 时间。</summary>
  36. public static DateTime GetUtcFromNtp(string server = "pool.ntp.org", int port = 123, int timeout = 1000)
  37. {
  38. try
  39. {
  40. var addresses = Dns.GetHostEntry(server).AddressList;
  41. if (addresses.Length > 0)
  42. {
  43. var endpoint = new IPEndPoint(addresses[0], port);
  44. return GetUtcFromNtp(endpoint, timeout);
  45. }
  46. }
  47. catch { }
  48. return new DateTime(1, 0, 0, 0, 0, 0, 0, DateTimeKind.Utc);
  49. }
  50. /// <summary>从 NTP 服务器获取 UTC 时间。</summary>
  51. public static DateTime GetUtcFromNtp(IPEndPoint endpoint, int timeout = 1000)
  52. {
  53. try
  54. {
  55. var request = new byte[48];
  56. request[0] = 0x1B;
  57. var response = new byte[48];
  58. response[0] = 0x1B;
  59. var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  60. socket.Connect(endpoint);
  61. socket.ReceiveTimeout = timeout;
  62. socket.Send(request);
  63. socket.Receive(response);
  64. socket.Close();
  65. const byte replytime = 40;
  66. ulong secondspart = BitConverter.ToUInt32(response, replytime);
  67. ulong secondsfraction = BitConverter.ToUInt32(response, replytime + 4);
  68. secondspart = SwapEndian(secondspart);
  69. secondsfraction = SwapEndian(secondsfraction);
  70. ulong milliseconds = (secondspart * 1000) + ((secondsfraction * 1000) / 0x100000000UL);
  71. var utc = (new DateTime(1900, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds(milliseconds);
  72. return utc;
  73. }
  74. catch { }
  75. return new DateTime(1, 0, 0, 0, 0, 0, 0, DateTimeKind.Utc);
  76. }
  77. private static uint SwapEndian(ulong x)
  78. {
  79. var a = ((x & 0x000000ff) << 24);
  80. var b = ((x & 0x0000ff00) << 8);
  81. var c = ((x & 0x00ff0000) >> 8);
  82. var d = ((x & 0xff000000) >> 24);
  83. return (uint)(a + b + c + d);
  84. }
  85. #endregion
  86. #region ARP
  87. #if NET40 || NET461
  88. /// <summary>发送 ARP 请求,获取目标 IP 地址对应设备的 MAC 地址,MAC 格式为 01-23-45-67-89-AB。</summary>
  89. /// <param name="ip">目标 IP 地址。</param>
  90. /// <returns>MAC 地址。</returns>
  91. public static string SendARP(string ip)
  92. {
  93. if (!string.IsNullOrEmpty(ip))
  94. {
  95. try
  96. {
  97. var ipa = IPAddress.Parse(ip);
  98. uint dip = BitConverter.ToUInt32(ipa.GetAddressBytes(), 0);
  99. ulong mac = 0;
  100. uint len = 6;
  101. uint err = IpHlpApi.SendARP(dip, 0, ref mac, ref len);
  102. byte[] bytes = BitConverter.GetBytes(mac);
  103. return BitConverter.ToString(bytes, 0, 6);
  104. }
  105. catch { }
  106. }
  107. return "";
  108. }
  109. #endif
  110. #endregion
  111. #region Puny Code
  112. /// <summary></summary>
  113. public static string ToPunyCode(string chinese)
  114. {
  115. if (string.IsNullOrEmpty(chinese)) return "";
  116. try { return new IdnMapping().GetAscii(chinese); }
  117. catch { return chinese; }
  118. }
  119. /// <summary></summary>
  120. public static string FromPunyCode(string punycode)
  121. {
  122. if (string.IsNullOrEmpty(punycode)) return "";
  123. try { return new IdnMapping().GetUnicode(punycode); }
  124. catch { return punycode; }
  125. }
  126. #endregion
  127. #region IP
  128. /// <summary>获取本地计算机的计算机名。</summary>
  129. public static string LocalHost
  130. {
  131. get
  132. {
  133. var hn = Dns.GetHostName();
  134. return string.IsNullOrEmpty(hn) ? "" : hn;
  135. }
  136. }
  137. /// <summary>本地计算机的 IP 地址。</summary>
  138. public static List<string> LocalIP
  139. {
  140. get
  141. {
  142. var list = new List<string>();
  143. var he = Dns.GetHostEntry(Dns.GetHostName());
  144. foreach (var ip in he.AddressList)
  145. {
  146. list.Add(ip.ToString());
  147. }
  148. return list;
  149. }
  150. }
  151. /// <summary>判断 IPv4 地址格式是否正确。</summary>
  152. public static bool IsIP(string ipv4)
  153. {
  154. try
  155. {
  156. if (string.IsNullOrEmpty(ipv4)) return false;
  157. var split = ipv4.Split('.');
  158. if (split.Length != 4) return false;
  159. for (int i = 0; i < 4; i++)
  160. {
  161. var n = Convert.ToInt32(split[i]);
  162. if (n < 0 || n > 255) return false;
  163. if (n.ToString() != split[i]) return false;
  164. }
  165. return true;
  166. }
  167. catch { }
  168. return false;
  169. }
  170. /// <summary>对目标地址进行解析。</summary>
  171. public static string Resolve(string host)
  172. {
  173. try
  174. {
  175. if (IsIP(host))
  176. {
  177. var ip = IPAddress.Parse(host);
  178. var he = Dns.GetHostEntry(ip);
  179. return he.HostName;
  180. }
  181. else
  182. {
  183. var ip = "";
  184. var dn = host.ToLower();
  185. var he = Dns.GetHostEntry(dn);
  186. var ts = "";
  187. var on = he.Aliases;
  188. he = Dns.GetHostEntry(dn);
  189. for (int i = 0; i < on.Length; i++) ts = ts + on[i].ToString() + ",";
  190. ts = "";
  191. var al = he.AddressList;
  192. for (int i = 0; i < al.Length; i++) ts = ts + al[i].ToString() + ",";
  193. ip = ts;
  194. if (ip.Length > 0)
  195. {
  196. if (ip.Substring(ip.Length - 1, 1) == ",") ip = ip.Substring(0, ip.Length - 1);
  197. }
  198. return ip;
  199. }
  200. }
  201. catch { }
  202. return "";
  203. }
  204. /// <summary>将由字符串表示的 IPv4 地址转换为 32 位整数。</summary>
  205. public static int GetNumber(IPAddress ipv4)
  206. {
  207. try
  208. {
  209. var ba = ipv4.GetAddressBytes();
  210. return BitConverter.ToInt32(ba, 0);
  211. }
  212. catch { return 0; }
  213. }
  214. /// <summary>转换 IP 地址格式。</summary>
  215. public static string GetPlainAddress(IPAddress address)
  216. {
  217. try { return address.ToString(); }
  218. catch { return ""; }
  219. }
  220. /// <summary>转换 IP 地址格式。</summary>
  221. public static string GetPlainAddress(IPEndPoint endpoint)
  222. {
  223. try { return GetPlainAddress(endpoint.Address); }
  224. catch { return ""; }
  225. }
  226. /// <summary>转换 IP 地址格式。</summary>
  227. public static IPAddress GetIPAddress(string address)
  228. {
  229. try { return IPAddress.Parse(address); }
  230. catch { return new IPAddress(0); }
  231. }
  232. /// <summary>转换 IP 地址格式。</summary>
  233. public static IPEndPoint GetIPEndPoint(string address, int port)
  234. {
  235. try { return new IPEndPoint(IPAddress.Parse(address), NumberUtility.RestrictValue(port, 0, ushort.MaxValue)); }
  236. catch { return new IPEndPoint(0, 0); }
  237. }
  238. /// <summary>转换 IP 地址格式。</summary>
  239. public static IPEndPoint GetIPEndPoint(IPAddress address, int port)
  240. {
  241. try { return new IPEndPoint(address, NumberUtility.RestrictValue(port, 0, ushort.MaxValue)); }
  242. catch { return new IPEndPoint(0, 0); }
  243. }
  244. /// <summary>转换 IP 地址格式。</summary>
  245. public static IPEndPoint GetIPEndPoint(EndPoint endpoint)
  246. {
  247. try { return (IPEndPoint)endpoint; }
  248. catch { return new IPEndPoint(0, 0); }
  249. }
  250. /// <summary>判断私有 IP 地址。</summary>
  251. public static bool FromLAN(string ipv4)
  252. {
  253. if (ipv4.IsEmpty()) return false;
  254. // localhost
  255. if (ipv4 == "::1") return true;
  256. if (ipv4 == "127.0.0.1") return true;
  257. // IPv4
  258. var a = ipv4.Split('.');
  259. if (a.Length != 4) return false;
  260. switch (a[0])
  261. {
  262. case "10":
  263. return true;
  264. case "172":
  265. var a1 = TextUtility.GetInt32(a[1]);
  266. if (a1 >= 16 && a1 <= 31) return true;
  267. break;
  268. case "192":
  269. if (a[1] == "168") return true;
  270. break;
  271. }
  272. return false;
  273. }
  274. #endregion
  275. #region HTTP
  276. /// <summary>GET</summary>
  277. public static HttpClient HttpGet(string url, int timeout = 30000)
  278. {
  279. return HttpClient.SimpleGet(url, timeout);
  280. }
  281. /// <summary>POST</summary>
  282. public static HttpClient HttpPost(string url, byte[] data, int timeout = 30000, string type = "application/octet-stream")
  283. {
  284. return HttpClient.SimplePost(url, data, timeout, type);
  285. }
  286. /// <summary>POST text/plain</summary>
  287. public static HttpClient HttpPost(string url, string text, int timeout = 30000, string type = "text/plain")
  288. {
  289. return HttpClient.SimpleText(url, text, timeout, type);
  290. }
  291. /// <summary>POST application/x-www-form-urlencoded</summary>
  292. public static HttpClient HttpPost(string url, IDictionary<string, string> form, int timeout = 30000)
  293. {
  294. return HttpClient.SimpleForm(url, form, timeout);
  295. }
  296. /// <summary>POST application/x-www-form-urlencoded</summary>
  297. public static HttpClient HttpPost(string url, TextSet form, int timeout = 30000)
  298. {
  299. return HttpClient.SimpleForm(url, form, timeout);
  300. }
  301. #endregion
  302. }
  303. }