Commit d1fae4cc authored by shrabbit's avatar shrabbit
Browse files

全部基础功能完成

parent 2f9b6803
Loading
Loading
Loading
Loading

.idea/.idea.LPing/.idea/misc.xml

deleted100644 → 0
+0 −25
Original line number Diff line number Diff line
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="AIAssistantCustomInstructionsStorage">
    <option name="instructions">
      <map>
        <entry key="AIAssistant.VCS.GenerateCommitMessage">
          <value>
            <AIAssistantStoredInstruction>
              <option name="actionId" value="AIAssistant.VCS.GenerateCommitMessage" />
              <option name="content" value="Avoid overly verbose descriptions or unnecessary details.&#10;&#10;TEXT LANGUAGE: ZH-CN" />
            </AIAssistantStoredInstruction>
          </value>
        </entry>
        <entry key="AIAssistant.WriteDocumentation.CSharp">
          <value>
            <AIAssistantStoredInstruction>
              <option name="actionId" value="AIAssistant.WriteDocumentation.CSharp" />
              <option name="content" value="Do not return example code, do not use @author or @version or @since tags.&#10;DO NOT generate example usage.&#10;DO NOT generate usage example.&#10;DO NOT use html tags such as &lt;p&gt;, &lt;lu&gt;, &lt;li&gt;.&#10;DO NOT generate documentation for type member properties.&#10;TEXT LANGUAGE: ZH-CN&#10;Write C# doc." />
            </AIAssistantStoredInstruction>
          </value>
        </entry>
      </map>
    </option>
  </component>
</project>
 No newline at end of file
+255 −2
Original line number Diff line number Diff line
namespace LPing;
using System.Globalization;

namespace LPing;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Hello, World!");
        try
        {
            if (args.Length == 0 || args.Contains("/?") || args.Contains("--help"))
            {
                Help();
                return;
            }

            ReadArgumentsAndRun(args);
        }
        catch (Exception e)
        {
#if DEBUG
            Console.WriteLine(e);
#endif
            Console.WriteLine(e.Message);
        }
    }

    private static void ReadArgumentsAndRun(string[] args)
    {
        string target = args[0];

        if (target == "all")
        {
            var localNetworkDevices = GetLocalNetworkDevices();
            foreach (var device in localNetworkDevices)
            {
                Run(device,
                    FindArgument<float>(args, "-f", "Frequency"),
                    FindArgument<uint>(args, "-p", "ParallelCount"),
                    FindArgument<uint>(args, "-l", "BufferSize"),
                    FindArgument<uint>(args, "-s", "FPS"),
                    FindArgument<uint>(args, "-o", "Timeout"),
                    FindArgument<uint>(args, "-c", "Count"),
                    args.Contains("-nl"));
            }
        }
        else
        {
            var frequency = FindArgument<float>(args, "-f", "Frequency");
            var parallel = FindArgument<uint>(args, "-p", "ParallelCount");
            var size = FindArgument<uint>(args, "-l", "BufferSize");

            uint? count = null;
            bool noLimit = args.Contains("-nl");
            if (!noLimit)
                count = FindArgument<uint>(args, "-c", "Count");

            var fps = FindArgument<uint>(args, "-s", "FPS");
            var timeout = FindArgument<uint>(args, "-o", "Timeout");

            Run(
                target,
                frequency,
                parallel,
                size,
                fps,
                timeout,
                count,
                noLimit);
        }
    }

    private static List<string> GetLocalNetworkDevices()
    {
        var devices = new List<string>();
        var networkInterfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();

        foreach (var networkInterface in networkInterfaces)
        {
            if (networkInterface.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up)
            {
                var ipProperties = networkInterface.GetIPProperties();
                var unicastAddresses = ipProperties.UnicastAddresses;

                foreach (var unicastAddress in unicastAddresses)
                {
                    if (unicastAddress.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                    {
                        var ipAddress = unicastAddress.Address;
                        var subnetMask = unicastAddress.IPv4Mask;

                        var networkAddress = new System.Net.IPAddress(BitConverter.ToUInt32(
                            BitConverter.GetBytes(ipAddress.GetAddressBytes()[0] & subnetMask.GetAddressBytes()[0]),
                            0));
                        var broadcastAddress = new System.Net.IPAddress(BitConverter.ToUInt32(
                            BitConverter.GetBytes(ipAddress.GetAddressBytes()[0] | ~subnetMask.GetAddressBytes()[0]),
                            0));

                        ulong start = BitConverter.ToUInt32(networkAddress.GetAddressBytes(), 0);
                        ulong end = BitConverter.ToUInt32(broadcastAddress.GetAddressBytes(), 0);

                        for (ulong i = start; i <= end; i++)
                        {
                            byte[] addressBytes = BitConverter.GetBytes((uint)i);
                            if (BitConverter.IsLittleEndian)
                            {
                                Array.Reverse(addressBytes);
                            }

                            devices.Add(new System.Net.IPAddress(addressBytes).ToString());
                        }
                    }
                }
            }
        }

        return devices;
    }

    private static T FindArgument<T>(string[] args, string point, string argName)
        where T : IParsable<T>
    {
        if (T.TryParse(FindNextArgument(args, point) ?? throw new ArgumentException($"{argName} not found."),
                CultureInfo.InvariantCulture,
                out var res))
            return res;
        throw new ArgumentException($"{argName} must be a \"{typeof(T).Name}\".");
    }

    private static string? FindNextArgument(string[] args, string point)
    {
        var idx = Array.IndexOf(args, point);
        if (idx == -1 || idx + 1 >= args.Length)
            return null;
        return args[idx + 1];
    }

    private static void Help()
    {
        Console.WriteLine("shRabbit LPing\n");
        Console.WriteLine(
            "Usages: lping [HostName]:String [-p ParallelCount]:UInt32 [-f Frequency]:Single [-l Size]:UInt32, (0, 65500] [-s FPS]:Uint32 [-o Timeout]:Uint32 [[-c Count]:UInt32 | [-nl]]\n");
        Console.WriteLine("Options: ");
        Console.WriteLine("\t HostName: \t\t Target hostname (all = LAN).");
        Console.WriteLine("\t -p ParallelCount: \t Control the ping action parallel number.");
        Console.WriteLine("\t -f Frequency: \t\t Control the ping action frequency per second.");
        Console.WriteLine("\t -l Size: \t\t Control the ping buffer size.");
        Console.WriteLine("\t -s FPS: \t\t Refresh information rate.");
        Console.WriteLine("\t -o Timeout: \t\t Throw timeout packet.");
        Console.WriteLine("\t -c Count: \t\t Sent ping packet total number (pre ping actions).");
        Console.WriteLine("\t -nl: \t\t\t No total number limit.");
    }

    private static void Run(
        string target,
        float frequency,
        uint parallel,
        uint buffer,
        uint fps,
        uint timeout,
        uint? count,
        bool noLimit)
    {
        List<Ping> pings = [];
        List<Task> pingTasks = [];
        for (var i = 0; i < parallel; i++)
        {
            var p = new Ping(target, buffer, timeout);
            pings.Add(p);
            pingTasks.Add(Task.Run(async () =>
            {
                try
                {
                    if (noLimit)
                        while (true)
                        {
                            await p.DoPing();
                            await Task.Delay((int)(1000 / frequency));
                        }

                    for (var j = 0; j < count; j++)
                    {
                        await p.DoPing();
                        await Task.Delay((int)(1000 / frequency));
                    }
                }
                catch (Exception e)
                {
#if DEBUG
                    Console.WriteLine(e);
#endif
                    Console.WriteLine(e.Message);
                }
            }));
        }

        ShowDisplay(pings, fps, target);
        // Wait for all ping tasks to complete
        Task.WaitAll(pingTasks.ToArray());
    }

    private static async void ShowDisplay(ICollection<Ping> pings, uint fps, string target)
    {
        try
        {
            Console.Clear();
            while (true)
            {
                Console.CursorVisible = false;
                Console.SetCursorPosition(0, 0);
                Console.WriteLine($"Ping {target}: ");
                var i = 0;
                foreach (var ping in pings)
                {
                    Console.SetCursorPosition(0, i + 1);
                    Console.Write(
                        $"[{i}] \tTotal: \t{ping.Count}, \tSuccess: \t{ping.SuccessCount}, \tLoss Rate: {ping.LossRate:F2}%, \tTime: {ping.Time.ToString() ?? "--"}");
                    i++;
                }

                await Task.Delay((int)(1000 / fps));
            }
        }
        catch (Exception e)
        {
#if DEBUG
            Console.WriteLine(e);
#endif
            Console.WriteLine(e.Message);
        }
        finally
        {
            Console.CursorVisible = true;
        }
    }
}

class Ping(string host, uint buffer, uint timeout)
{
    private TimeSpan _timeout = TimeSpan.FromMilliseconds(timeout);
    private byte[] _buffer = new byte[buffer];

    public int Count { get; private set; }
    public int SuccessCount { get; private set; }
    public int? Time { get; private set; }

    public double LossRate => (Count - SuccessCount) / (double)Count * 100;

    public async Task DoPing()
    {
        System.Net.NetworkInformation.Ping ping = new();
        var reply = await ping.SendPingAsync(host, _timeout, _buffer);

        if (reply.Status == System.Net.NetworkInformation.IPStatus.Success)
        {
            Time = (int?)reply.RoundtripTime;
            SuccessCount++;
        }

        Count++;
    }
}
 No newline at end of file