使用等待运行并行HTTP请求

问题描述 投票:0回答:1

所以这是来自> [Using Parallel Processing in C# to test a site's ability to withstand a DDOS

的随身物品

我使用此MS KB文章作为示例的基础,只是我不想通过单击按钮运行它,而只是启动并随后触发“攻击”方法的控制台脚本,该方法循环遍历X URL,并在返回时返回。 example from MS刚刚向Microsoft URLS发出了3个请求。

为了使它更像KB文章,我将按钮单击替换为在控制台应用程序运行时调用的Main程序,该程序依次调用Attack(),而后者仅(目前仅尝试获取3 URLS)。在真实的代码中,我有一个循环,但是我需要使这第一点起作用,这样我才能理解我在做什么错。

但是我在命令提示符下运行它时得到的却是...。

C:\Users\XXX>"C:\Users\XXX\Documents\Visual Studio 2017\Projects\DOSBot\DOSBot
\bin\Release\DOSBot.exe" "https://www.google.com" 1000
10/05/2020 00:00:00: starting script

然后结束,没有从我期望的HTTP请求返回消息。

控制台脚本的代码如下:

using System;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.ComponentModel.DataAnnotations;


namespace AsyncExample_MultipleTasks
{
    class Program
    {
        // Replaced the MS KB article example of hitting a button with just a Main constructor that runs from the console. I am passing arguments in at the moment URL and no of Requests to make but not currently using them as I want to understand why the MS KB example of making 3 requests is not working
        public static void Main(string[] args)
        {
            if (args.Length > 0)
            {

                string url = args[0];
                int no = Convert.ToInt32(args[1]);

                ShowDebug("starting script");

                // Attack DOS = new Attack(url,no);
                Attack DOS = new Attack();

                // Moved from the Attack() constructor but made no difference
                DOS.StartAttack();

                // The job just seems to end with no error message and DOS.StartAttack() seems to be skipped over
            }
        }

        public static void ShowDebug(string msg)
        {
            string debugmsg = DateTime.Now.Date.ToString() + ": " + msg;

            Console.WriteLine(debugmsg);
        }
    }


    public class Attack
    {
        private int Counter = 0; // will hold no of actual HTTP requests completed
        private string URL; // URL to hit
        private int ReqNo; // No of HTTP request to make

        public Attack()//string url, int reqNo=100)
        {
            this.URL = "http://www.google.com";// url;
            this.ReqNo = 100; //reqNo;

            //Tried calling this from here but now from the Main Program Constructor but makes no difference
            //this.StartAttack();
        }

        // Tried calling this from the constructor above (commented out), and now from the main Program but neither do anything different
        public async void StartAttack()
        {
            await CreateMultipleTasksAsync();
        }

        // This would be replaced by my loop with one URL to request and X no of times to request it.
        private async Task CreateMultipleTasksAsync()
        {
            // Declare an HttpClient object, and increase the buffer size. The  
            // default buffer size is 65,536.  
            HttpClient client =
                new HttpClient() { MaxResponseContentBufferSize = 1000000 };

            // Create and start the tasks. As each task finishes, DisplayResults
            // displays its length.  
            Task<int> download1 =
                ProcessURLAsync("https://msdn.microsoft.com", client);
            Task<int> download2 =
                ProcessURLAsync("https://msdn.microsoft.com/library/hh156528(VS.110).aspx", client);
            Task<int> download3 =
                ProcessURLAsync("https://msdn.microsoft.com/library/67w7t67f.aspx", client);

            // Await each task.  
            int length1 = await download1;
            int length2 = await download2;
            int length3 = await download3;

            int total = length1 + length2 + length3;

            // Display the total count for the downloaded websites.  
            Program.ShowDebug("\r\n\r\nTotal bytes returned:  {total}\r\n");
        }

        async Task<int> ProcessURLAsync(string url, HttpClient client)
        {
            var byteArray = await client.GetByteArrayAsync(url);
            DisplayResults(url, byteArray);
            return byteArray.Length;
        }

        // Why is this not firing on return of the HTTP request?
        private void DisplayResults(string url, byte[] content)
        {
            // Display the length of each website. The string format
            // is designed to be used with a monospaced font, such as  
            // Lucida Console or Global Monospace.  
            var bytes = content.Length;
            // Strip off the "https://".  
            var displayURL = url.Replace("https://", "");
            Program.ShowDebug($"\n{displayURL,-58} {bytes,8}");
        }
    }
}

因此,根本不会调用DisplayResults方法,从理论上讲,从我阅读的内容来看,当HTTP响应返回无字节数等信息时,应将其触发。但是,我根本看不到它在运行。

我是否缺少参考文献或其他内容?我在Visual Studio 2017的64位Windows笔记本电脑上使用.NET 4.6.1。

c# http parallel-processing async-await ddos
1个回答
2
投票

异步编程中有一些重要的原理需要理解:

  1. 异步!=并行。您的代码中没有任何“并行”事件。

    • “ Parallel”表示两行代码正在同时执行。这只能通过多个线程来完成。这一切都是关于事情[[run。
    • “异步”是指您在一段代码等待来自外部(网络请求,文件系统等)的答复时继续执行代码,而不是坐在那里等待。这一切都是关于事物[[wait
  2. 由于您在等待期间继续执行代码,因此需要某种方式来知道请求实际何时完成。这就是Task对象的用途。这就是任何异步方法都应返回Task的原因。如果它没有返回Task,您将永远无法知道它何时完成或
  3. if
  4. 实际上是否成功完成。

    这使我们进入await的工作。 await关键字作用于Task对象。当await作用于不完整的Task时,方法

  5. 返回
  6. 。如果方法签名指示应返回Task,则返回Task。如果方法签名为void,则不会返回任何内容-但该方法仍会返回。

了解所有这些,让我们逐步了解程序中发生的事情:

[Main()呼叫DOS.StartAttack()

    [StartAttack()运行并调用CreateMultipleTasksAsync()
  1. CreateMultipleTasksAsync()运行。
  2. ProcessURLAsync()被调用。发送网络请求后,将返回不完整的Task。当收到回复时,Task对象将告诉您。
  3. [ProcessURLAsync()的其他两个调用发生相同的事情。
  4. await download1,因为download1是不完整的Task,所以CreateMultipleTasksAsync()返回其自己的不完整Task
  5. 执行返回到StartAttack()
  6. await关键字看到从Task返回的不完整CreateMultipleTasksAsync()并返回。由于方法签名为void,因此不返回任何内容。
  7. 执行返回到Main()。由于没有其他可运行的程序,因此程序结束。
  • 这里的问题是,因为StartAttack()void,所以您不知道何时完成异步请求。要解决此问题:
    1. 更改StartAttack()以返回Task而不是void
  • [await DOS.StartAttack()中的Main()

  • Main()的签名更改为:

  • public static async Task Main(string[] args)

    也就是说,只要您使用的是C#7.1或更高版本。那时Main方法可以开始返回Task

    Microsoft在Asynchronous programming with async and await上有一些写得很好的文章。他们值得一读。该链接只是第一篇文章。您将在该页面左侧的目录中找到其余的内容。
  • © www.soinside.com 2019 - 2024. All rights reserved.