-
Notifications
You must be signed in to change notification settings - Fork 6
/
Program.cs
106 lines (87 loc) · 4.25 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using HttpBomb.OptionValidators;
using McMaster.Extensions.CommandLineUtils;
using McMaster.Extensions.CommandLineUtils.Validation;
namespace HttpBomb
{
class Program
{
static void Main(string[] args)
{
var app = new CommandLineApplication(){
Name = "HttpBomb",
Description = "Http bombarding tool. Show no mercy."
};
app.HelpOption();
var threadsOption = app.Option<int>("-n|--number <N>", "[Required] Number of threads to run", CommandOptionType.SingleValue);
threadsOption.Validators.Add(new ThreadValidator());
var durationOption = app.Option<int>("-d|--duration <SECONDS>", "[Required] Time to run in seconds", CommandOptionType.SingleValue);
durationOption.Validators.Add(new DurationValidator());
var urlOption = app.Option("-u|--url <URL>", "[Required] Url to hit", CommandOptionType.SingleValue);
urlOption.Validators.Add(new UrlValidator());
var timeoutOption = app.Option<int>("-t|--timeout <SECONDS>", "[Optional] Http client timeout in seconds", CommandOptionType.SingleValue);
Func<int?> getTimeoutValue = () => timeoutOption.HasValue()? new Nullable<int>(timeoutOption.ParsedValue) : null;
app.OnExecute(() => Execute(threadsOption.ParsedValue, durationOption.ParsedValue, urlOption.Value(), getTimeoutValue()));
app.Execute(args);
}
static void Execute(int threads, int duration, string url, int? timeout)
{
long successCount = 0;
long failCount = 0;
Action incrementSuccess = () => Interlocked.Increment(ref successCount);
Action incrementFail = () => Interlocked.Increment(ref failCount);
Func<long> getSuccessCount = () => successCount;
Func<long> getFailCount = () => failCount;
var stopWatch = Stopwatch.StartNew();
var client = new HttpClient();
if (timeout.HasValue)
client.Timeout = TimeSpan.FromSeconds(timeout.Value);
Enumerable.Range(0, threads)
.ToList()
.ForEach(_ => Task.Run(async () => await MainThread(client, url, incrementSuccess, incrementFail)));
Task.Run(() => CounterThread(stopWatch, getSuccessCount, getFailCount));
Thread.Sleep(TimeSpan.FromSeconds(duration));
stopWatch.Stop();
ShowResult(stopWatch, successCount, failCount);
}
static async Task MainThread(HttpClient client, string url, Action onSuccess, Action onFail)
{
while (true)
await client.GetAsync(url).ContinueWith(t => {
if (t.IsCanceled || t.Result.StatusCode != HttpStatusCode.OK)
onFail();
else
onSuccess();
});
}
static void CounterThread(Stopwatch sw, Func<long> getSuccessCount, Func<long> getFailCount)
{
long lastSuccessCount = 0;
double lastSwTime = 0;
while(true){
var swTime = sw.Elapsed.TotalSeconds;
var successCount = getSuccessCount();
var failCount = getFailCount();
var successRate = Math.Round((successCount - lastSuccessCount) / (swTime - lastSwTime), 2);
lastSuccessCount = successCount;
lastSwTime = swTime;
Console.WriteLine($"Success count: {successCount}, Fail count: {failCount}, Success/sec: {successRate} Req/sec");
Thread.Sleep(TimeSpan.FromSeconds(1));
}
}
private static void ShowResult(Stopwatch sw, long successCount, long failCount)
{
Console.WriteLine("");
Console.WriteLine($"Results: Total success: {successCount}, Total fail: {failCount}, Average success/second: {successCount/sw.Elapsed.TotalSeconds}");
}
}
}