using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; namespace FastGithub.Scanner { /// /// RawSocket的ping功能 /// static class RawSocketPing { private static readonly byte[] echoRequestPacket = Convert.FromHexString("0800F6FF0100000000000000"); private static readonly byte[] icmpReceiveBuffer = new byte[72]; /// /// 获取是否支持 /// public static bool IsSupported { get; private set; } /// /// RawSocket的ping功能 /// static RawSocketPing() { try { new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp).Dispose(); IsSupported = true; } catch (Exception) { IsSupported = false; } } /// /// ping目标ip /// /// /// 等待时间 /// 取消令牌 /// ping通的ip public static async Task> PingAsync(IEnumerable destAddresses, TimeSpan timeWait, CancellationToken cancellationToken = default) { using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp) { Ttl = 128, DontFragment = false }; socket.Bind(new IPEndPoint(IPAddress.Any, 0)); using var cancellationTokenSource = new CancellationTokenSource(); using var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, cancellationTokenSource.Token); var receiveTask = ReceiveAsync(socket, linkedTokenSource.Token); var distinctDestAddresses = destAddresses.Distinct(); foreach (var address in distinctDestAddresses) { var remoteEndPoint = new IPEndPoint(address, 0); await socket.SendToAsync(echoRequestPacket, SocketFlags.None, remoteEndPoint); } await Task.Delay(timeWait, cancellationToken); cancellationTokenSource.Cancel(); socket.Close(); var hashSet = await receiveTask; hashSet.IntersectWith(distinctDestAddresses); return hashSet; } /// /// 循环接收任务 /// /// /// /// private static async Task> ReceiveAsync(Socket socket, CancellationToken cancellationToken) { await Task.Yield(); var hashSet = new HashSet(); var remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); while (cancellationToken.IsCancellationRequested == false) { try { var result = await socket.ReceiveFromAsync(icmpReceiveBuffer, SocketFlags.None, remoteEndPoint); if (result.RemoteEndPoint is IPEndPoint ipEndPoint) { hashSet.Add(ipEndPoint.Address); } } catch (SocketException ex) when (ex.SocketErrorCode == SocketError.OperationAborted) { break; } catch (Exception) { } } return hashSet; } } }