RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1190481
Accepted
Zekoyka
Zekoyka
Asked:2021-10-15 05:50:25 +0000 UTC2021-10-15 05:50:25 +0000 UTC 2021-10-15 05:50:25 +0000 UTC

开放端口的扫描过程非常慢

  • 772
// работа на тему Информационная безопасность
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp3
{
    class Program
    {
        private static string IP = "";

        static void Main(string[] args)
        {
            Console.Title = "PortScanner";
            UserInput();
            PortScan();
            Console.ReadKey();
        }

        private static void UserInput()
        {
            Console.Write("IP Address:", ConsoleColor.White);
            IP = Console.ReadLine();
        }

        private static void PortScan()
        {
            Console.Clear();
            TcpClient Scan = new TcpClient();
            foreach (int s in Ports)
            {
                try
                {
                    Scan.Connect(IP, s);
                    Console.WriteLine($"[{s}] | OPEN", ConsoleColor.Green);
                }
                catch
                {
                    Console.WriteLine($"[{s}] | CLOSED", ConsoleColor.Red);
                }
            }
        }

        private static int[] Ports = new int[]
        {
        1,
        2,
        3,
        80,
        };

    }
}

        

扫描指定IP上的端口很长时间很长时间。如何加快进程?

如何在一行中指定端口?(这样输入很愚蠢,用逗号分隔)

c#
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    EvgeniyZ
    2021-10-15T08:20:46Z2021-10-15T08:20:46Z

    如果很简单,那么答案是:使用异步,不要等待另一个检查完成!
    您需要在代码中做几件事:

    1. Main从void到async Task。
    2. 将创建一个Task检查一个端口的任务 ( )。
      • 也就是说,我们PortScan扔掉所有多余的东西(循环,清除控制台)
      • 该参数需要一个端口
      • 从 更改void为async Task。
      • 将其更改.Connect()为.ConnectAsync(),添加await。
      • 我们TcpClient把自己包裹起来using,因为它必须被关闭!
    3. 让我们将您的端口数组转换为任务,然后我们通过Task.WhenAll().

    结果,会出现这样的情况:

    private static string IP = "";
    
    static async Task Main(string[] args)
    {
        Console.Title = "PortScanner";
        UserInput();
        Console.Clear();
    
        var tasks = Ports.Select(x => PortScan(x));
        await Task.WhenAll(tasks);
    
        Console.ReadKey();
    }
    
    private static void UserInput()
    {
        Console.Write("IP Address:", ConsoleColor.White);
        IP = Console.ReadLine();
    }
    
    private static async Task PortScan(int port)
    {
        using TcpClient Scan = new TcpClient();
    
        try
        {
            await Scan.ConnectAsync(IP, port);
            Console.WriteLine($"[{port}] | OPEN", ConsoleColor.Green);
        }
        catch
        {
            Console.WriteLine($"[{port}] | CLOSED", ConsoleColor.Red);
        }
    }
    
    private static int[] Ports = new int[]
    {
    1,
    2,
    3,
    80,
    };
    

    现在您的端口检查将异步进行,即无需等待前一次检查完成。

    但是,你有很多可以改进的地方,让我们来做吧:

    1. UserInput()- 为什么此方法不返回结果,而是将其写入某个静态变量?毕竟,它的任务是询问用户并给我们他的工作答案。让我们用不同的方式写它:

      static string AskUser(string message)
      {
          Write($"{message}: ");
          return ReadLine();
      }
      

      现在该方法为我们提供了用户输入的内容。

    2. 显示彩色消息- 在这里您还应该使用一种方便的方法,例如:

      static void ColoredText(string title, string text, ConsoleColor color)
      {
          Write($"{title}: ");
          ForegroundColor = color;
          WriteLine(text);
          ResetColor();
      }
      

      现在您可以方便地显示文本,例如端口的状态。

    3. IP - 学习使用正确的类型,而不是一些基本的类型。在 c# 中有一个特殊的 ip 类IPAddress,使用它!让我们创建一个询问用户 ip 的方法,如果不正确,则要求一个新的,如果输入成功,它将给我们IPAddress:

      static IPAddress AskIp(string message)
      {
          while (true)
          {
              var reply = AskUser(message);
              if (IPAddress.TryParse(reply, out var ip))
              {
                  return ip;
              }
              else
              {
                  ColoredText(reply, "Не является IP", ConsoleColor.Red);
                  ReadKey();
                  Clear();
              }
          }
      }
      
    4. 让我们改进扫描方法- 现在任务正在等待超时,这也可以更改:

      • 让我们创建一个单独的方法(客户端上的某种包装器,最好放在单独的类中)尝试建立连接,但也会异步启动某个计时器,如果运行会抛出错误快点:

        static async Task TimeoutConnectAsync(IPAddress ip, int port, TimeSpan connectTimeout = default)
        {
            if (connectTimeout == default) 
                connectTimeout = TimeSpan.FromMilliseconds(500);
        
            using var client = new TcpClient();
        
            var cancelTask = Task.Delay(connectTimeout);
            var connectTask = client.ConnectAsync(ip, port);
        
            await Task.WhenAny(connectTask, cancelTask);
        
            if (cancelTask.IsCompleted)
            {
                throw new TimeoutException();
            }
        }
        
      • 好吧,检查一个端口本身的任务:

        static async Task CheckPortAsync(IPAddress ip, int port, TimeSpan connectTimeout = default)
        {
            bool result;
        
            try
            {
                await TimeoutConnectAsync(ip, port, connectTimeout);
                result = true;
            }
            catch
            {
                result = false;
            }
        
            ColoredText($"{ip}:{port}", result ? "Открыт" : "Закрыт", result ? ConsoleColor.Green : ConsoleColor.Red);
        }
        

      现在,当检查一个端口时,如果它在 500 毫秒内不可用,我们认为它“关闭”。

    5. 多重检查- 您不需要使用端口初始化新数组,只需使用params逗号分隔的所有端口并将其传递给该方法。让我们创建一个新方法,它将获取一个端口列表,并一次检查它们:

      static async Task CheckPortsAsync(IPAddress ip, params int[] ports)
      {
          var tasks = ports.Select(x => CheckPortAsync(ip, x));
          await Task.WhenAll(tasks);
      }
      

      它被简单地称为await CheckPortsAsync(ip, 1, 2, 3, 80);

    我这里没有讲 OOP 和其他特性,只知道在一个类中写不好,把它分解成不同的类,负责一件事。

    所有代码:

    static async Task Main()
    {
        var ip = AskIp("IP Address");
        await CheckPortsAsync(ip, 1, 2, 3, 80);
    }
    
    static async Task CheckPortAsync(IPAddress ip, int port, TimeSpan connectTimeout = default)
    {
        bool result;
    
        try
        {
            await TimeoutConnectAsync(ip, port, connectTimeout);
            result = true;
        }
        catch
        {
            result = false;
        }
    
        ColoredText($"{ip}:{port}", result ? "Открыт" : "Закрыт", result ? ConsoleColor.Green : ConsoleColor.Red);
    }
    
    static async Task CheckPortsAsync(IPAddress ip, params int[] ports)
    {
        var tasks = ports.Select(x => CheckPortAsync(ip, x));
        await Task.WhenAll(tasks);
    }
    
    static async Task TimeoutConnectAsync(IPAddress ip, int port, TimeSpan connectTimeout = default)
    {
        if (connectTimeout == default)
            connectTimeout = TimeSpan.FromMilliseconds(500);
    
        using var client = new TcpClient();
    
        var cancelTask = Task.Delay(connectTimeout);
        var connectTask = client.ConnectAsync(ip, port);
    
        await Task.WhenAny(connectTask, cancelTask);
    
        if (cancelTask.IsCompleted)
        {
            throw new TimeoutException();
        }
    }
    
    static void ColoredText(string title, string text, ConsoleColor color)
    {
        Write($"{title}: ");
        ForegroundColor = color;
        WriteLine(text);
        ResetColor();
    }
    
    static string AskUser(string message)
    {
        Write($"{message}: ");
        return ReadLine();
    }
    static IPAddress AskIp(string message)
    {
        while (true)
        {
            var reply = AskUser(message);
            if (IPAddress.TryParse(reply, out var ip))
            {
                return ip;
            }
            else
            {
                ColoredText(reply, "Не является IP", ConsoleColor.Red);
                ReadKey();
                Clear();
            }
        }
    }
    

    执行结果:

    结果

    其实就这些了,我给你指明了方向,剩下的就看你了!

    • PS为什么ReadLine()不Console.ReadLine()呢?因为它对我来说更方便)它是在using static System.Console;.
    • PSS 由于这里进行的是异步,结果可以“笨拙地”显示出来,在这里你已经可以和lock其他杂乱无章的东西一起玩了。好吧,总的来说,以一种好的方式,最好是Task<bool>在完成所有任务后,显示结果。验证方法不需要输出任何东西,这本质上是违反SOLID的,所以想想吧!

    你可以想出一些原创的东西,比如 1-80、123、443、500-2000

    如果您需要这个,那么您可以编写类似以下方法的内容:

    private static IEnumerable<int> ParseRange(string range) => 
        range.Split(',')
        .Select(x => x.Split('-'))
        .Select(x => (First: int.Parse(x.First()), Last: int.Parse(x.Last())))
        .SelectMany(x => Enumerable.Range(x.First, x.Last - x.First + 1))
        .OrderBy(x => x);
    

    在这里,其实一切都很简单:

    1. 我们用逗号打破一切,最终会给我们一个字符串的集合。
    2. 我们将这个集合中的每个值用 分隔-,这实际上会给我们一个由字符串集合组成的集合。
    3. 现在我们需要一个包含每个集合的第一个和最后一个值的对象。如果只有一个值,则 min 和 max 将相同。(First: 1, Last: 2)是一个元组(您也可以使用匿名类型 ( new {First: 1, Last: 2})。
    4. 我们仍然需要生成数字,因为有Enumerable.Range(),它将给出指定范围内的数字。
    5. 一切,结果排序。

    我们称之为:

    var ports = ParseRange("1, 5-10, 13, 80, 100-100, 115-120")
    

    结果:

    1
    5
    6
    7
    8
    9
    10
    13
    80
    100
    115
    116
    117
    118
    119
    120
    
    • 7

相关问题

  • 使用嵌套类导出 xml 文件

  • 分层数据模板 [WPF]

  • 如何在 WPF 中为 ListView 手动创建列?

  • 在 2D 空间中,Collider 2D 挂在玩家身上,它对敌人的重量相同,我需要它这样当它们碰撞时,它们不会飞向不同的方向。统一

  • 如何在 c# 中使用 python 神经网络来创建语音合成?

  • 如何知道类中的方法是否属于接口?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5