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.

359 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. int r = 0;
  155. try
  156. {
  157. if (!string.IsNullOrEmpty(ipv4))
  158. {
  159. var a = ipv4.Split('.');
  160. if (a.Length == 4)
  161. {
  162. for (int i = 0; i < 4; i++)
  163. {
  164. int n = Convert.ToInt32(a[i]);
  165. if ((n >= 0) && (n <= 255)) r += 1;
  166. }
  167. }
  168. }
  169. }
  170. catch { }
  171. return (r == 4) ? true : false;
  172. }
  173. /// <summary>对目标地址进行解析。</summary>
  174. public static string Resolve(string host)
  175. {
  176. try
  177. {
  178. if (IsIP(host))
  179. {
  180. var ip = IPAddress.Parse(host);
  181. var he = Dns.GetHostEntry(ip);
  182. return he.HostName;
  183. }
  184. else
  185. {
  186. var ip = "";
  187. var dn = host.ToLower();
  188. var he = Dns.GetHostEntry(dn);
  189. var ts = "";
  190. var on = he.Aliases;
  191. he = Dns.GetHostEntry(dn);
  192. for (int i = 0; i < on.Length; i++) ts = ts + on[i].ToString() + ",";
  193. ts = "";
  194. var al = he.AddressList;
  195. for (int i = 0; i < al.Length; i++) ts = ts + al[i].ToString() + ",";
  196. ip = ts;
  197. if (ip.Length > 0)
  198. {
  199. if (ip.Substring(ip.Length - 1, 1) == ",") ip = ip.Substring(0, ip.Length - 1);
  200. }
  201. return ip;
  202. }
  203. }
  204. catch { }
  205. return "";
  206. }
  207. /// <summary>将由字符串表示的 IPv4 地址转换为 32 位整数。</summary>
  208. public static int GetNumber(IPAddress ipv4)
  209. {
  210. try
  211. {
  212. var ba = ipv4.GetAddressBytes();
  213. return BitConverter.ToInt32(ba, 0);
  214. }
  215. catch { return 0; }
  216. }
  217. /// <summary>转换 IP 地址格式。</summary>
  218. public static string GetPlainAddress(IPAddress address)
  219. {
  220. try { return address.ToString(); }
  221. catch { return ""; }
  222. }
  223. /// <summary>转换 IP 地址格式。</summary>
  224. public static string GetPlainAddress(IPEndPoint endpoint)
  225. {
  226. try { return GetPlainAddress(endpoint.Address); }
  227. catch { return ""; }
  228. }
  229. /// <summary>转换 IP 地址格式。</summary>
  230. public static IPAddress GetIPAddress(string address)
  231. {
  232. try { return IPAddress.Parse(address); }
  233. catch { return new IPAddress(0); }
  234. }
  235. /// <summary>转换 IP 地址格式。</summary>
  236. public static IPEndPoint GetIPEndPoint(string address, int port)
  237. {
  238. try { return new IPEndPoint(IPAddress.Parse(address), NumberUtility.RestrictValue(port, 0, ushort.MaxValue)); }
  239. catch { return new IPEndPoint(0, 0); }
  240. }
  241. /// <summary>转换 IP 地址格式。</summary>
  242. public static IPEndPoint GetIPEndPoint(IPAddress address, int port)
  243. {
  244. try { return new IPEndPoint(address, NumberUtility.RestrictValue(port, 0, ushort.MaxValue)); }
  245. catch { return new IPEndPoint(0, 0); }
  246. }
  247. /// <summary>转换 IP 地址格式。</summary>
  248. public static IPEndPoint GetIPEndPoint(EndPoint endpoint)
  249. {
  250. try { return (IPEndPoint)endpoint; }
  251. catch { return new IPEndPoint(0, 0); }
  252. }
  253. /// <summary>判断私有 IP 地址。</summary>
  254. public static bool FromLAN(string ipv4)
  255. {
  256. if (ipv4.IsEmpty()) return false;
  257. // localhost
  258. if (ipv4 == "::1") return true;
  259. if (ipv4 == "127.0.0.1") return true;
  260. // IPv4
  261. var a = ipv4.Split('.');
  262. if (a.Length != 4) return false;
  263. switch (a[0])
  264. {
  265. case "10":
  266. return true;
  267. case "172":
  268. var a1 = TextUtility.GetInt32(a[1]);
  269. if (a1 >= 16 && a1 <= 31) return true;
  270. break;
  271. case "192":
  272. if (a[1] == "168") return true;
  273. break;
  274. }
  275. return false;
  276. }
  277. #endregion
  278. #region HTTP
  279. /// <summary>GET</summary>
  280. public static HttpClient HttpGet(string url, int timeout = 30000)
  281. {
  282. return HttpClient.SimpleGet(url, timeout);
  283. }
  284. /// <summary>POST</summary>
  285. public static HttpClient HttpPost(string url, byte[] data, int timeout = 30000, string type = "application/octet-stream")
  286. {
  287. return HttpClient.SimplePost(url, data, timeout, type);
  288. }
  289. /// <summary>POST text/plain</summary>
  290. public static HttpClient HttpPost(string url, string text, int timeout = 30000, string type = "text/plain")
  291. {
  292. return HttpClient.SimpleText(url, text, timeout, type);
  293. }
  294. /// <summary>POST application/x-www-form-urlencoded</summary>
  295. public static HttpClient HttpPost(string url, IDictionary<string, string> form, int timeout = 30000)
  296. {
  297. return HttpClient.SimpleForm(url, form, timeout);
  298. }
  299. /// <summary>POST application/x-www-form-urlencoded</summary>
  300. public static HttpClient HttpPost(string url, TextSet form, int timeout = 30000)
  301. {
  302. return HttpClient.SimpleForm(url, form, timeout);
  303. }
  304. #endregion
  305. }
  306. }