我正在创建一个网页flooder来测试我服务器上的某些安全性。 我有这段代码:
static void Main(string[] args)
{
string url;
int times;
Console.WriteLine("Inserisci l'indirizzo(pagina specifica) da floodare");
url = Console.ReadLine();
Console.WriteLine("Quante volte?");
times = Int32.Parse(Console.ReadLine());
System.Net.ServicePointManager.DefaultConnectionLimit = 350;
var block = new System.Threading.Tasks.Dataflow.ActionBlock<int>(async i =>
{
try
{
await Work(i, url);
}
catch (Exception e)
{
}
}, new System.Threading.Tasks.Dataflow.ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 350 });
for(int i = 0; i < times; i++)
{
block.Post(i);
}
block.Complete();
Task.WaitAll(block.Completion);
}
private static async Task<bool> Work(int i, string url)
{
if (i % 1000 == 0)
Console.WriteLine(i);
new WebClient().UploadValuesTaskAsync(url, new System.Collections.Specialized.NameValueCollection());
//await Task.Delay(1);
return true;
}
}
它的工作做得很好,但它有一个问题。如果我设置的请求数量非常高(如200万或更多),它会使用很多内存。在130万请求它使用3.3gb的RAM。我试图处理所有东西,以任何方式释放ram但似乎block变量存储每个线程直到它完成。我该如何解决这个问题?
答案 0 :(得分:2)
在Work
中,您不必等待IO完成。这使Work
非常快速地完成。这有效地禁用了您想要的速率限制(MaxDegreeOfParallelism = 350
)。
工作开始的速度比完成时快得多。这就是工作项积累和消耗内存的原因。
等待IO完成。
答案 1 :(得分:1)
我发现了什么。您正在使用WebClient,但不要将其丢弃。
工作方法应该是这样的:
private static async Task<bool> Work(int i, string url)
{
if (i % 1000 == 0)
Console.WriteLine(i);
// Must dispose to avoid leaks
using (var wc = new WebClient())
{
await wc.UploadValuesTaskAsync(url, new System.Collections.Specialized.NameValueCollection());
}
//await Task.Delay(1);
return true;
}
<强>更新强> 我使用HttpWebRequest和异步方法BeginGetResponse来解决您的问题。完整代码为https://dotnetfiddle.net/ZecQku:
namespace HttpWebRequest_HighIntesive
{
using System;
using System.Diagnostics;
using System.Net;
using System.Threading;
class ThreadParam
{
public int RequestsCount { get; private set; }
public CountdownEvent CountdownEvent { get; private set; }
public ThreadParam(int requestsCount, CountdownEvent countdownEvent)
{
RequestsCount = requestsCount;
CountdownEvent = countdownEvent;
}
}
class FinistRequestParam
{
public CountdownEvent CountdownEvent { get; private set; }
public HttpWebRequest HttpWebRequest { get; private set; }
public FinistRequestParam(CountdownEvent countdownEvent, HttpWebRequest httpWebRequest)
{
CountdownEvent = countdownEvent;
HttpWebRequest = httpWebRequest;
}
}
public class Program
{
static Uri _uri;
static volatile int _numberOfFinishedRequests;
static double _prevMemoryMb = 0;
public static int Main(string[] args)
{
int numOfRequests;
Console.Write("Enter URL(full format, for example, http://google.ru): ");
var url = Console.ReadLine();
if (!Uri.TryCreate(url, UriKind.RelativeOrAbsolute, out _uri)){
Console.WriteLine("Invalid URL. Exiting"); return -1;
}
Console.Write("Enter number of requests: ");
numOfRequests = Int32.Parse(Console.ReadLine());
Console.WriteLine("");
DoParallelRequests(numOfRequests);
Console.WriteLine("Finished. Press 'Enter' to quit");
Console.ReadLine();
return 0;
}
private static void DoParallelRequests(int numOfRequests)
{
// Play with DefaultConnectionLimit
// Increasing this value will increase speed, but also increase memory consumption
System.Net.ServicePointManager.DefaultConnectionLimit = 350;
Console.WriteLine("DefaultConnectionLimit: {0}", System.Net.ServicePointManager.DefaultConnectionLimit);
int threadCnt = Environment.ProcessorCount;
Console.WriteLine("Num of threads which creates HttpWebRequest: {0}", threadCnt);
// Initialize CountDownEvent with numOfRequests
CountdownEvent countDownOnTimes = new CountdownEvent(numOfRequests);
// Create timer for statistics
using (var timer = new Timer(TimerStatisticHanlder, Stopwatch.StartNew(), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(5)))
{
// Create thread array
Thread[] threads = new Thread[threadCnt];
// Initialize each thread and start it
for (int i = 0; i < threads.Length; i++)
{
threads[i] = new Thread(ThreadMethod);
// HACK Hope numOfRequests % threadCnt == 0 (evenly divisible)
// Start thread
threads[i].Start(new ThreadParam(numOfRequests / threadCnt, countDownOnTimes));
}
// Will wait untill all request processed
countDownOnTimes.Wait();
}
}
static void TimerStatisticHanlder(object obj)
{
Stopwatch sw = obj as Stopwatch;
// Calculate average speed
var aveageSpeed = Math.Round(_numberOfFinishedRequests / sw.Elapsed.TotalSeconds, 2);
// Get total memory
var totalMemoryMb = Math.Round((double)GC.GetTotalMemory(false) / 1024 / 1024);
// Calculate memory delta
var memoryDeltaMb = totalMemoryMb - _prevMemoryMb;
// Print out statistics
Console.WriteLine("{0} Processed requests: {1}, Average speed: {2} requests per/s, Used memory: {3} Mbytes, Memory delta: {4}", DateTime.Now.ToString("HH:mm:ss"), _numberOfFinishedRequests, aveageSpeed, totalMemoryMb, memoryDeltaMb);
// Store total memory for delta calculation
_prevMemoryMb = totalMemoryMb;
}
private static void ThreadMethod(object state)
{
var threadParam = state as ThreadParam;
for (int i = 0; i <= threadParam.RequestsCount; i++)
{
// Create HttpWebRequest
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_uri);
// Start it asynchronous
request.BeginGetResponse(new AsyncCallback(FinishRequest), new FinistRequestParam(threadParam.CountdownEvent, request));
}
}
private static void FinishRequest(IAsyncResult result)
{
var reqParam = result.AsyncState as FinistRequestParam;
var request = reqParam.HttpWebRequest;
try
{
// Just end response
HttpWebResponse response = request.EndGetResponse(result) as HttpWebResponse;
// Release all resources
response.GetResponseStream().Dispose();
response.Close();
(request as IDisposable).Dispose();
}
catch { } // Don't care about exceptions
// Mark yet another request finished
reqParam.CountdownEvent.Signal();
// Increment total number of finished requests
Interlocked.Increment(ref _numberOfFinishedRequests);
}
}
}