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.

416 lines
14 KiB

using Apewer.Network;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
namespace Apewer
{
/// <summary></summary>
public class NetworkUtility
{
#region UDP
/// <summary>唤醒局域网中拥有指定 MAC 地址的设备。</summary>
/// <param name="mac">被唤醒设备的 MAC 地址,必须是长度为 6 的字节数组。</param>
public static void WakeOnLan(byte[] mac)
{
if (mac.Length != 6) return;
var uc = new System.Net.Sockets.UdpClient();
uc.Connect(IPAddress.Broadcast, 65535);
var pack = new List<byte>();
// 前 6 字节为 0xFF。
for (int i = 0; i < 6; i++) pack.Add(255);
// 目标 MAC 地址重复 16 次。
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 6; j++) pack.Add(mac[j]);
}
// 发送 102 字节数据。
uc.Send(pack.ToArray(), pack.Count);
uc.Close();
}
/// <summary>从 NTP 服务器获取 UTC 时间。</summary>
/// <remarks>
/// 通用 NTP 服务器:<br/>
/// Worldwide: pool.ntp.org<br/>
/// Asia: asia.pool.ntp.org<br/>
/// China: edu.ntp.org.cn<br/>
/// China: us.ntp.org.cn<br/>
/// Europe: europe.pool.ntp.org<br/>
/// North: America north-america.pool.ntp.org<br/>
/// Oceania: oceania.pool.ntp.org<br/>
/// South America: south-america.pool.ntp.org<br/>
/// Windows: time.windows.com<br/>
/// Windows: time.nist.gov<br/>
/// </remarks>
public static Class<DateTime> GetUtcFromNtp(string server = "pool.ntp.org", int port = 123, int timeout = 1000)
{
try
{
var addresses = Dns.GetHostEntry(server).AddressList;
if (addresses.Length > 0)
{
var endpoint = new IPEndPoint(addresses[0], port);
return GetUtcFromNtp(endpoint, timeout);
}
}
catch { }
return null;
}
/// <summary>从 NTP 服务器获取 UTC 时间。</summary>
public static Class<DateTime> GetUtcFromNtp(IPEndPoint endpoint, int timeout = 1000)
{
try
{
var request = new byte[48];
request[0] = 0x1B;
var response = new byte[48];
response[0] = 0x1B;
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Connect(endpoint);
socket.SendTimeout = timeout;
socket.ReceiveTimeout = timeout;
socket.Send(request);
socket.Receive(response);
socket.Close();
const byte replytime = 40;
ulong secondspart = BitConverter.ToUInt32(response, replytime);
ulong secondsfraction = BitConverter.ToUInt32(response, replytime + 4);
secondspart = SwapEndian(secondspart);
secondsfraction = SwapEndian(secondsfraction);
ulong milliseconds = (secondspart * 1000) + ((secondsfraction * 1000) / 0x100000000UL);
var utc = (new DateTime(1900, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).AddMilliseconds(milliseconds);
return new Class<DateTime>(utc);
}
catch { }
return null;
}
private static uint SwapEndian(ulong x)
{
var a = ((x & 0x000000ff) << 24);
var b = ((x & 0x0000ff00) << 8);
var c = ((x & 0x00ff0000) >> 8);
var d = ((x & 0xff000000) >> 24);
return (uint)(a + b + c + d);
}
#endregion
#region Puny Code
/// <summary></summary>
public static string ToPunyCode(string chinese)
{
if (string.IsNullOrEmpty(chinese)) return "";
try { return new IdnMapping().GetAscii(chinese); }
catch { return chinese; }
}
/// <summary></summary>
public static string FromPunyCode(string punycode)
{
if (string.IsNullOrEmpty(punycode)) return "";
try { return new IdnMapping().GetUnicode(punycode); }
catch { return punycode; }
}
#endregion
#region IP
/// <summary>获取本地计算机的计算机名。</summary>
public static string LocalHost
{
get => Dns.GetHostName() ?? "";
}
/// <summary>本地计算机的所有 IP 地址。</summary>
public static IPAddress[] LocalIP
{
get => Dns.GetHostEntry(Dns.GetHostName()).AddressList;
}
/// <summary>判断 IPv4 地址格式是否正确。</summary>
public static bool IsIP(string ipv4)
{
try
{
if (string.IsNullOrEmpty(ipv4)) return false;
var split = ipv4.Split('.');
if (split.Length != 4) return false;
for (int i = 0; i < 4; i++)
{
var n = Convert.ToInt32(split[i]);
if (n < 0 || n > 255) return false;
if (n.ToString() != split[i]) return false;
}
return true;
}
catch { }
return false;
}
/// <summary>对目标地址进行解析。</summary>
public static string Resolve(string host)
{
try
{
if (IsIP(host))
{
var ip = IPAddress.Parse(host);
var he = Dns.GetHostEntry(ip);
return he.HostName;
}
else
{
var ip = "";
var dn = host.ToLower();
var he = Dns.GetHostEntry(dn);
var ts = "";
var on = he.Aliases;
he = Dns.GetHostEntry(dn);
for (int i = 0; i < on.Length; i++) ts = ts + on[i].ToString() + ",";
ts = "";
var al = he.AddressList;
for (int i = 0; i < al.Length; i++) ts = ts + al[i].ToString() + ",";
ip = ts;
if (ip.Length > 0)
{
if (ip.Substring(ip.Length - 1, 1) == ",") ip = ip.Substring(0, ip.Length - 1);
}
return ip;
}
}
catch { }
return "";
}
/// <summary>将由字符串表示的 IPv4 地址转换为 32 位整数。</summary>
public static int GetNumber(IPAddress ipv4)
{
try
{
var ba = ipv4.GetAddressBytes();
return BitConverter.ToInt32(ba, 0);
}
catch { return 0; }
}
/// <summary>转换 IP 地址格式。</summary>
public static string GetPlainAddress(IPAddress address)
{
try { return address.ToString(); }
catch { return ""; }
}
/// <summary>转换 IP 地址格式。</summary>
public static string GetPlainAddress(IPEndPoint endpoint)
{
try { return GetPlainAddress(endpoint.Address); }
catch { return ""; }
}
/// <summary>转换 IP 地址格式。</summary>
public static IPAddress GetIPAddress(string address)
{
try { return IPAddress.Parse(address); }
catch { return new IPAddress(0); }
}
/// <summary>转换 IP 地址格式。</summary>
public static IPEndPoint GetIPEndPoint(string address, int port)
{
try { return new IPEndPoint(IPAddress.Parse(address), NumberUtility.Restrict(port, 0, ushort.MaxValue)); }
catch { return new IPEndPoint(0, 0); }
}
/// <summary>转换 IP 地址格式。</summary>
public static IPEndPoint GetIPEndPoint(IPAddress address, int port)
{
try { return new IPEndPoint(address, NumberUtility.Restrict(port, 0, ushort.MaxValue)); }
catch { return new IPEndPoint(0, 0); }
}
/// <summary>转换 IP 地址格式。</summary>
public static IPEndPoint GetIPEndPoint(System.Net.EndPoint endpoint)
{
try { return (IPEndPoint)endpoint; }
catch { return new IPEndPoint(0, 0); }
}
/// <summary>判断私有 IP 地址。</summary>
public static bool FromLAN(string ipv4)
{
if (ipv4.IsEmpty()) return false;
// localhost
if (ipv4 == "::1") return true;
if (ipv4 == "127.0.0.1") return true;
// IPv4
var a = ipv4.Split('.');
if (a.Length != 4) return false;
switch (a[0])
{
case "10":
return true;
case "172":
var a1 = NumberUtility.Int32(a[1]);
if (a1 >= 16 && a1 <= 31) return true;
break;
case "192":
if (a[1] == "168") return true;
break;
}
return false;
}
#endregion
#region HTTP
/// <summary>GET</summary>
public static HttpClient HttpGet(string url, int timeout = 30000)
{
return HttpClient.SimpleGet(url, timeout);
}
/// <summary>POST</summary>
public static HttpClient HttpPost(string url, byte[] data, int timeout = 30000, string type = "application/octet-stream")
{
return HttpClient.SimplePost(url, data, timeout, type);
}
/// <summary>POST text/plain</summary>
public static HttpClient HttpPost(string url, string text, int timeout = 30000, string type = "text/plain")
{
return HttpClient.SimpleText(url, text, timeout, type);
}
/// <summary>POST application/x-www-form-urlencoded</summary>
public static HttpClient HttpPost(string url, IDictionary<string, string> form, int timeout = 30000)
{
return HttpClient.SimpleForm(url, form, timeout);
}
/// <summary>POST application/x-www-form-urlencoded</summary>
public static HttpClient HttpPost(string url, TextSet form, int timeout = 30000)
{
return HttpClient.SimpleForm(url, form, timeout);
}
/// <summary>获取 HTTP 状态的文本。</summary>
public static string HttpStatusDescription(int code)
{
switch (code)
{
case 100: return "Continue";
case 101: return "Switching Protocols";
case 102: return "Processing";
case 200: return "OK";
case 201: return "Created";
case 202: return "Accepted";
case 203: return "Non-Authoritative Information";
case 204: return "No Content";
case 205: return "Reset Content";
case 206: return "Partial Content";
case 207: return "Multi-Status";
case 300: return "Multiple Choices";
case 301: return "Moved Permanently";
case 302: return "Found";
case 303: return "See Other";
case 304: return "Not Modified";
case 305: return "Use Proxy";
case 307: return "Temporary Redirect";
case 400: return "Bad Request";
case 401: return "Unauthorized";
case 402: return "Payment Required";
case 403: return "Forbidden";
case 404: return "Not Found";
case 405: return "Method Not Allowed";
case 406: return "Not Acceptable";
case 407: return "Proxy Authentication Required";
case 408: return "Request Timeout";
case 409: return "Conflict";
case 410: return "Gone";
case 411: return "Length Required";
case 412: return "Precondition Failed";
case 413: return "Request Entity Too Large";
case 414: return "Request-Uri Too Long";
case 415: return "Unsupported Media Type";
case 416: return "Requested Range Not Satisfiable";
case 417: return "Expectation Failed";
case 422: return "Unprocessable Entity";
case 423: return "Locked";
case 424: return "Failed Dependency";
case 426: return "Upgrade Required"; // RFC 2817
case 500: return "Internal Server Error";
case 501: return "Not Implemented";
case 502: return "Bad Gateway";
case 503: return "Service Unavailable";
case 504: return "Gateway Timeout";
case 505: return "Http Version Not Supported";
case 507: return "Insufficient Storage";
default: return null;
}
}
#endregion
#region Port
private static List<int> ListActivePort(IPEndPoint[] endpoints)
{
var list = new List<int>(endpoints.Length);
foreach (var endpoint in endpoints)
{
var port = endpoint.Port;
if (list.Contains(port)) continue;
list.Add(port);
}
list.Sort();
list.Capacity = list.Count;
return list;
}
/// <summary>列出活动的 TCP 端口。</summary>
public static List<int> ListActiveTcpPort()
{
return ListActivePort(IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners());
}
/// <summary>列出活动的 UDP 端口。</summary>
public static List<int> ListActiveUdpPort()
{
return ListActivePort(IPGlobalProperties.GetIPGlobalProperties().GetActiveUdpListeners());
}
#endregion
}
}