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.

410 lines
14 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. using Apewer.Network;
  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Globalization;
  6. using System.Net;
  7. using System.Net.NetworkInformation;
  8. using System.Net.Sockets;
  9. using System.Runtime.InteropServices;
  10. using System.Text;
  11. namespace Apewer
  12. {
  13. /// <summary></summary>
  14. public class NetworkUtility
  15. {
  16. #region UDP
  17. /// <summary>唤醒局域网中拥有指定 MAC 地址的设备。</summary>
  18. /// <param name="mac">被唤醒设备的 MAC 地址,必须是长度为 6 的字节数组。</param>
  19. public static void WakeOnLan(byte[] mac)
  20. {
  21. if (mac.Length != 6) return;
  22. var uc = new System.Net.Sockets.UdpClient();
  23. uc.Connect(IPAddress.Broadcast, 65535);
  24. var pack = new List<byte>();
  25. // 前 6 字节为 0xFF。
  26. for (int i = 0; i < 6; i++) pack.Add(255);
  27. // 目标 MAC 地址重复 16 次。
  28. for (int i = 0; i < 16; i++)
  29. {
  30. for (int j = 0; j < 6; j++) pack.Add(mac[j]);
  31. }
  32. // 发送 102 字节数据。
  33. uc.Send(pack.ToArray(), pack.Count);
  34. uc.Close();
  35. }
  36. /// <summary>从 NTP 服务器获取 UTC 时间。</summary>
  37. /// <remarks>
  38. /// 通用 NTP 服务器:<br/>
  39. /// Worldwide: pool.ntp.org<br/>
  40. /// Asia: asia.pool.ntp.org<br/>
  41. /// China: edu.ntp.org.cn<br/>
  42. /// China: us.ntp.org.cn<br/>
  43. /// Europe: europe.pool.ntp.org<br/>
  44. /// North: America north-america.pool.ntp.org<br/>
  45. /// Oceania: oceania.pool.ntp.org<br/>
  46. /// South America: south-america.pool.ntp.org<br/>
  47. /// Windows: time.windows.com<br/>
  48. /// Windows: time.nist.gov<br/>
  49. /// </remarks>
  50. public static Class<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 { }
  62. return null;
  63. }
  64. /// <summary>从 NTP 服务器获取 UTC 时间。</summary>
  65. public static Class<DateTime> GetUtcFromNtp(IPEndPoint endpoint, int timeout = 1000)
  66. {
  67. try
  68. {
  69. var request = new byte[48];
  70. request[0] = 0x1B;
  71. var response = new byte[48];
  72. response[0] = 0x1B;
  73. var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  74. socket.Connect(endpoint);
  75. socket.SendTimeout = timeout;
  76. socket.ReceiveTimeout = timeout;
  77. socket.Send(request);
  78. socket.Receive(response);
  79. socket.Close();
  80. const byte replytime = 40;
  81. ulong secondspart = BitConverter.ToUInt32(response, replytime);
  82. ulong secondsfraction = BitConverter.ToUInt32(response, replytime + 4);
  83. secondspart = SwapEndian(secondspart);
  84. secondsfraction = SwapEndian(secondsfraction);
  85. ulong milliseconds = (secondspart * 1000) + ((secondsfraction * 1000) / 0x100000000UL);
  86. var utc = (new DateTime(1900, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds(milliseconds);
  87. return new Class<DateTime>(utc);
  88. }
  89. catch { }
  90. return null;
  91. }
  92. private static uint SwapEndian(ulong x)
  93. {
  94. var a = ((x & 0x000000ff) << 24);
  95. var b = ((x & 0x0000ff00) << 8);
  96. var c = ((x & 0x00ff0000) >> 8);
  97. var d = ((x & 0xff000000) >> 24);
  98. return (uint)(a + b + c + d);
  99. }
  100. #endregion
  101. #region Puny Code
  102. /// <summary></summary>
  103. public static string ToPunyCode(string chinese)
  104. {
  105. if (string.IsNullOrEmpty(chinese)) return "";
  106. try { return new IdnMapping().GetAscii(chinese); }
  107. catch { return chinese; }
  108. }
  109. /// <summary></summary>
  110. public static string FromPunyCode(string punycode)
  111. {
  112. if (string.IsNullOrEmpty(punycode)) return "";
  113. try { return new IdnMapping().GetUnicode(punycode); }
  114. catch { return punycode; }
  115. }
  116. #endregion
  117. #region IP
  118. /// <summary>获取本地计算机的计算机名。</summary>
  119. public static string LocalHost
  120. {
  121. get => Dns.GetHostName() ?? "";
  122. }
  123. /// <summary>本地计算机的所有 IP 地址。</summary>
  124. public static IPAddress[] LocalIP
  125. {
  126. get => Dns.GetHostEntry(Dns.GetHostName()).AddressList;
  127. }
  128. /// <summary>判断 IPv4 地址格式是否正确。</summary>
  129. public static bool IsIP(string ipv4)
  130. {
  131. try
  132. {
  133. if (string.IsNullOrEmpty(ipv4)) return false;
  134. var split = ipv4.Split('.');
  135. if (split.Length != 4) return false;
  136. for (int i = 0; i < 4; i++)
  137. {
  138. var n = Convert.ToInt32(split[i]);
  139. if (n < 0 || n > 255) return false;
  140. if (n.ToString() != split[i]) return false;
  141. }
  142. return true;
  143. }
  144. catch { }
  145. return false;
  146. }
  147. /// <summary>对目标地址进行解析。</summary>
  148. public static string Resolve(string host)
  149. {
  150. try
  151. {
  152. if (IsIP(host))
  153. {
  154. var ip = IPAddress.Parse(host);
  155. var he = Dns.GetHostEntry(ip);
  156. return he.HostName;
  157. }
  158. else
  159. {
  160. var ip = "";
  161. var dn = host.ToLower();
  162. var he = Dns.GetHostEntry(dn);
  163. var ts = "";
  164. var on = he.Aliases;
  165. he = Dns.GetHostEntry(dn);
  166. for (int i = 0; i < on.Length; i++) ts = ts + on[i].ToString() + ",";
  167. ts = "";
  168. var al = he.AddressList;
  169. for (int i = 0; i < al.Length; i++) ts = ts + al[i].ToString() + ",";
  170. ip = ts;
  171. if (ip.Length > 0)
  172. {
  173. if (ip.Substring(ip.Length - 1, 1) == ",") ip = ip.Substring(0, ip.Length - 1);
  174. }
  175. return ip;
  176. }
  177. }
  178. catch { }
  179. return "";
  180. }
  181. /// <summary>将由字符串表示的 IPv4 地址转换为 32 位整数。</summary>
  182. public static int GetNumber(IPAddress ipv4)
  183. {
  184. try
  185. {
  186. var ba = ipv4.GetAddressBytes();
  187. return BitConverter.ToInt32(ba, 0);
  188. }
  189. catch { return 0; }
  190. }
  191. /// <summary>转换 IP 地址格式。</summary>
  192. public static string GetPlainAddress(IPAddress address)
  193. {
  194. try { return address.ToString(); }
  195. catch { return ""; }
  196. }
  197. /// <summary>转换 IP 地址格式。</summary>
  198. public static string GetPlainAddress(IPEndPoint endpoint)
  199. {
  200. try { return GetPlainAddress(endpoint.Address); }
  201. catch { return ""; }
  202. }
  203. /// <summary>转换 IP 地址格式。</summary>
  204. public static IPAddress GetIPAddress(string address)
  205. {
  206. try { return IPAddress.Parse(address); }
  207. catch { return new IPAddress(0); }
  208. }
  209. /// <summary>转换 IP 地址格式。</summary>
  210. public static IPEndPoint GetIPEndPoint(string address, int port)
  211. {
  212. try { return new IPEndPoint(IPAddress.Parse(address), NumberUtility.Restrict(port, 0, ushort.MaxValue)); }
  213. catch { return new IPEndPoint(0, 0); }
  214. }
  215. /// <summary>转换 IP 地址格式。</summary>
  216. public static IPEndPoint GetIPEndPoint(IPAddress address, int port)
  217. {
  218. try { return new IPEndPoint(address, NumberUtility.Restrict(port, 0, ushort.MaxValue)); }
  219. catch { return new IPEndPoint(0, 0); }
  220. }
  221. /// <summary>转换 IP 地址格式。</summary>
  222. public static IPEndPoint GetIPEndPoint(System.Net.EndPoint endpoint)
  223. {
  224. try { return (IPEndPoint)endpoint; }
  225. catch { return new IPEndPoint(0, 0); }
  226. }
  227. /// <summary>判断私有 IP 地址。</summary>
  228. public static bool FromLAN(string ipv4)
  229. {
  230. if (ipv4.IsEmpty()) return false;
  231. // localhost
  232. if (ipv4 == "::1") return true;
  233. if (ipv4 == "127.0.0.1") return true;
  234. // IPv4
  235. var a = ipv4.Split('.');
  236. if (a.Length != 4) return false;
  237. switch (a[0])
  238. {
  239. case "10":
  240. return true;
  241. case "172":
  242. var a1 = NumberUtility.Int32(a[1]);
  243. if (a1 >= 16 && a1 <= 31) return true;
  244. break;
  245. case "192":
  246. if (a[1] == "168") return true;
  247. break;
  248. }
  249. return false;
  250. }
  251. #endregion
  252. #region HTTP
  253. /// <summary>GET</summary>
  254. public static HttpClient HttpGet(string url, int timeout = 30000)
  255. {
  256. return HttpClient.SimpleGet(url, timeout);
  257. }
  258. /// <summary>POST</summary>
  259. public static HttpClient HttpPost(string url, byte[] data, int timeout = 30000, string type = "application/octet-stream")
  260. {
  261. return HttpClient.SimplePost(url, data, timeout, type);
  262. }
  263. /// <summary>POST text/plain</summary>
  264. public static HttpClient HttpPost(string url, string text, int timeout = 30000, string type = "text/plain")
  265. {
  266. return HttpClient.SimpleText(url, text, timeout, type);
  267. }
  268. /// <summary>POST application/x-www-form-urlencoded</summary>
  269. public static HttpClient HttpPost(string url, IDictionary<string, string> form, int timeout = 30000)
  270. {
  271. return HttpClient.SimpleForm(url, form, timeout);
  272. }
  273. /// <summary>POST application/x-www-form-urlencoded</summary>
  274. public static HttpClient HttpPost(string url, TextSet form, int timeout = 30000)
  275. {
  276. return HttpClient.SimpleForm(url, form, timeout);
  277. }
  278. /// <summary>获取 HTTP 状态的文本。</summary>
  279. public static string HttpStatusDescription(int code)
  280. {
  281. switch (code)
  282. {
  283. case 100: return "Continue";
  284. case 101: return "Switching Protocols";
  285. case 102: return "Processing";
  286. case 200: return "OK";
  287. case 201: return "Created";
  288. case 202: return "Accepted";
  289. case 203: return "Non-Authoritative Information";
  290. case 204: return "No Content";
  291. case 205: return "Reset Content";
  292. case 206: return "Partial Content";
  293. case 207: return "Multi-Status";
  294. case 300: return "Multiple Choices";
  295. case 301: return "Moved Permanently";
  296. case 302: return "Found";
  297. case 303: return "See Other";
  298. case 304: return "Not Modified";
  299. case 305: return "Use Proxy";
  300. case 307: return "Temporary Redirect";
  301. case 400: return "Bad Request";
  302. case 401: return "Unauthorized";
  303. case 402: return "Payment Required";
  304. case 403: return "Forbidden";
  305. case 404: return "Not Found";
  306. case 405: return "Method Not Allowed";
  307. case 406: return "Not Acceptable";
  308. case 407: return "Proxy Authentication Required";
  309. case 408: return "Request Timeout";
  310. case 409: return "Conflict";
  311. case 410: return "Gone";
  312. case 411: return "Length Required";
  313. case 412: return "Precondition Failed";
  314. case 413: return "Request Entity Too Large";
  315. case 414: return "Request-Uri Too Long";
  316. case 415: return "Unsupported Media Type";
  317. case 416: return "Requested Range Not Satisfiable";
  318. case 417: return "Expectation Failed";
  319. case 422: return "Unprocessable Entity";
  320. case 423: return "Locked";
  321. case 424: return "Failed Dependency";
  322. case 426: return "Upgrade Required"; // RFC 2817
  323. case 500: return "Internal Server Error";
  324. case 501: return "Not Implemented";
  325. case 502: return "Bad Gateway";
  326. case 503: return "Service Unavailable";
  327. case 504: return "Gateway Timeout";
  328. case 505: return "Http Version Not Supported";
  329. case 507: return "Insufficient Storage";
  330. default: return null;
  331. }
  332. }
  333. #endregion
  334. #region Port
  335. private static int[] ActivePorts(IPEndPoint[] endpoints)
  336. {
  337. var list = new List<int>(endpoints.Length);
  338. foreach (var endpoint in endpoints)
  339. {
  340. var port = endpoint.Port;
  341. if (list.Contains(port)) continue;
  342. list.Add(port);
  343. }
  344. list.Sort();
  345. list.Capacity = list.Count;
  346. return list.ToArray();
  347. }
  348. /// <summary>列出活动的 TCP 端口。</summary>
  349. public static int[] ActiveTcpPorts() => ActivePorts(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
  350. /// <summary>列出活动的 UDP 端口。</summary>
  351. public static int[] ActiveUdpPorts() => ActivePorts(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
  352. #endregion
  353. }
  354. }