【C#】异步多线程 求助
本帖最后由 lizf2019 于 2024-8-16 19:24 编辑正在测试自己的服务器的抗打能力,因为市面上
直接可用的不太好找,遂想自己写一个
参考的代码测试后觉得难以使用,求助大佬如何实现这个:
1. C#每秒创建十个线程,每个线程通过不同代{过}{滤}理ip执行对url循环访问,之后每个线程在被创建的30s后自动销毁
2.每创建10个线程之前 使用Getip()更新ip库,之后每个代{过}{滤}理ip【格式为 ip:port 】从字符串数组Myip[]中调用:Myip n大于等于0小于等于9
3.代码是测自己服务器承受能力用的,如果有更好的模拟访问等方法欢迎大佬指出{:301_997:}
以下为ip格式,我通过
string[] ipPortPairs;
ipPortPairs = ipPortString.Split(' ');
将其存入数组
115.209.48.179:37608 116.7.173.115:31843 116.7.201.221:35131 119.132.91.47:39837 222.189.81.116:35243 175.146.211.176:34454 121.234.46.195:34738 111.72.196.138:33973 42.57.150.201:39846 111.72.134.86:40290
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
public class ServerStressTest
{
// 可配置的常量
private const int ThreadCount = 10; // 每秒创建的线程数
private const int RequestTimeoutSeconds = 30; // 每个请求的超时时间(秒)
private const int DelayBetweenBatches = 1000; // 每批线程之间的延迟时间(毫秒)
private const string RequestUrl = "http://your-url-here.com"; // 要访问的URL
private static readonly string[] Myip = new string; // 代{过}{滤}理IP数组
private static int ipIndex = 0;
public static void Main()
{
// 初始化 Myip 数组
for (int i = 0; i < Myip.Length; i++)
{
Myip = $"127.0.0.{i + 1}:8080"; // 示例IP:端口
}
StartProxyRequests();
}
public static void StartProxyRequests()
{
Task.Run(async () =>
{
while (true)
{
List<Task> tasks = new List<Task>();
for (int i = 0; i < ThreadCount; i++)
{
UpdateIpPortPairs(); // 每次循环前更新 IP 库
tasks.Add(CreateRequestTask());
}
await Task.WhenAll(tasks);
await Task.Delay(DelayBetweenBatches); // 等待指定的延迟时间后继续创建新的一批任务
}
});
}
private static Task CreateRequestTask()
{
return Task.Run(async () =>
{
string ipPort = GetNextIpPort(); // 获取下一个 IP:Port
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(RequestTimeoutSeconds)); // 设置超时为30秒
using (HttpClientHandler handler = new HttpClientHandler())
{
handler.Proxy = new System.Net.WebProxy($"http://{ipPort}");
handler.UseProxy = true;
using (HttpClient client = new HttpClient(handler))
{
try
{
Console.WriteLine($"使用代{过}{滤}理 {ipPort} 发送请求...");
// 发送请求
var response = await client.GetAsync(RequestUrl, cts.Token);
string result = await response.Content.ReadAsStringAsync();
Console.WriteLine($"来自 {ipPort} 的响应: {result.Substring(0, 100)}");
}
catch (TaskCanceledException)
{
Console.WriteLine($"代{过}{滤}理 {ipPort} 的任务已取消。");
}
catch (Exception ex)
{
Console.WriteLine($"代{过}{滤}理 {ipPort} 的任务发生错误: {ex.Message}");
}
}
}
});
}
private static string GetNextIpPort()
{
lock (Myip)
{
string ipPort = Myip;
ipIndex = (ipIndex + 1) % Myip.Length;
return ipPort;
}
}
private static void UpdateIpPortPairs()
{
// 在这里更新 Myip 数组
// 例如,可以从某个服务或数据库中获取新的代{过}{滤}理 IP 地址
Console.WriteLine("更新IP库...");
}
}
刺心 发表于 2024-8-16 18:24
using System;
using System.Collections.Generic;
using System.Net.Http;
好像有点问题 你测试服务器压力的话,我更建议你用python的locust框架进行测试,你有c#的基础上手python不会特别难;比你自己费劲写效果要好很多,你想模拟多少就模拟多少,公司服务器做压力测试的时候直接全断开了。给你参考下写法,不是特别难,稍微研究下就行。
都是高手呀 用Apache JMeter或locust进行压力测试试试? 本帖最后由 cfnm123 于 2024-8-16 22:01 编辑
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Json;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
class Program
{
private static readonly SemaphoreSlim semaphore = new SemaphoreSlim(100, 100);
private static readonly string[] Myip;
private static readonly IHost host;
private static readonly HttpClient httpClient;
private static readonly ILogger logger;
private static readonly string url = "http://your-target-url-here";
static Program()
{
// 初始化代{过}{滤}理IP列表
string ipPortString = "115.209.48.179:37608 116.7.173.115:31843 116.7.201.221:35131 119.132.91.47:39837 222.189.81.116:35243 175.146.211.176:34454 121.234.46.195:34738 111.72.196.138:33973 42.57.150.201:39846 111.72.134.86:40290";
Myip = ipPortString.Split(' ');
host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
services.AddLogging(builder => builder.AddConsole());
services.AddHttpClient();
})
.Build();
logger = host.Services.GetRequiredService<ILogger<Program>>();
httpClient = host.Services.GetRequiredService<IHttpClientFactory>().CreateClient();
}
static async Task Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
await UpdateIpListAsync();
await CreateThreadsAsync();
await Task.Delay(1000); // 每秒创建一次
}
logger.LogInformation("All threads have been created.");
Console.ReadKey();
}
static async Task CreateThreadsAsync()
{
for (int i = 0; i < 10; i++)
{
int index = i;
var task = ExecuteRequestAsync(index);
await task;
}
}
static async Task ExecuteRequestAsync(int index)
{
var handler = new HttpClientHandler
{
Proxy = new WebProxy(Myip),
UseProxy = true
};
using var client = new HttpClient(handler);
try
{
var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30)); // 设置30秒超时
var cancellationToken = cancellationTokenSource.Token;
while (!cancellationToken.IsCancellationRequested)
{
await semaphore.WaitAsync(cancellationToken);
try
{
var stopwatch = Stopwatch.StartNew();
var response = await client.GetAsync(url, cancellationToken);
stopwatch.Stop();
if (response.IsSuccessStatusCode)
{
logger.LogInformation($"Thread {index} made a request to {url} at {DateTime.Now.ToString("HH:mm:ss.fff")}. Response time: {stopwatch.ElapsedMilliseconds} ms.");
}
else
{
logger.LogWarning($"Thread {index} received a non-success status code: {response.StatusCode}.");
}
}
catch (OperationCanceledException)
{
logger.LogInformation($"Thread {index} was canceled.");
}
catch (Exception ex)
{
logger.LogError(ex, $"Error in thread {index}: {ex.Message}");
}
finally
{
semaphore.Release();
await Task.Delay(1000, cancellationToken); // 控制每个线程的请求频率
}
}
}
finally
{
logger.LogInformation($"Thread {index} has been terminated.");
}
}
static async Task UpdateIpListAsync()
{
// 这里可以添加逻辑来获取新的代{过}{滤}理IP列表
logger.LogInformation("Updating IP list...");
await Task.Delay(100); // 假设这里有一些延迟
}
} ”创建线程又关闭线程“ 的操作可以简化。根据楼主的第一个描述,当程序跑起来时,会有 20 个线程在工作,所以我用的是线程池,共创建 20 个线程。
还有,以下代码是结合 AI 写的。
```c#
using System;
using System.Net;
using System.Threading;
using System.Collections.Concurrent;
class Program
{
/// <summary>
/// 最大的线程数
/// </summary>
private const int maxThread = 20;
/// <summary>
/// 要访问的 URL
/// </summary>
private const string targetUrl = "http://xxx.com";
/// <summary>
/// 存储 IP 地址的队列,被线程共享
/// </summary>
private static readonly ConcurrentQueue<string> MyIp = new();
/// <summary>
/// 用于获取 IP 时的锁
/// </summary>
private static readonly object locker_for_getip = new();
static void Main()
{
// 循环创建线程到线程池中
for (int i = 0; i < maxThread; i++)
{
ThreadPool.QueueUserWorkItem(FetchUrl, i);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
/// <summary>
/// 发起网络请求的线程函数
/// </summary>
/// <param name="state"></param>
private static async void FetchUrl(object? state)
{
if (state is int thread_id)
{
while (true)
{
if (MyIp.TryDequeue(out var ipAddr))
{
Console.WriteLine($"Thread {thread_id} get Ip: {ipAddr}");
var proxy = new WebProxy(ipAddr, true);
var client = new HttpClient(new HttpClientHandler { Proxy = proxy, UseProxy = true });
await client.GetAsync(targetUrl);
Thread.Sleep(1000);
}
else
{
// 没有可用的 IP 地址,调用 GetIP 方法获取新的 IP 地址
GetIP();
}
}
}
}
/// <summary>
/// 更新 IP
/// </summary>
/// <param name="state"></param>
private static void GetIP()
{
if (MyIp.IsEmpty)
{
lock (locker_for_getip)
{
// 双重判断
if (MyIp.IsEmpty)
{
Console.WriteLine("Start get ip");
// 获取 ip,为了本地测试,使用 localhost 了
string[] ips = ["localhost:3000", "localhost:3000", "localhost:3000", "localhost:3000", "localhost:3000"];
foreach (var ip in ips)
{
MyIp.Enqueue(ip);
}
}
}
}
}
}
```
这是本机的测试结果,使用 `python -m http.server 3000` 开启了一个本地的服务器进行测试。
压测自己写不是很费劲么,为什么不用现成的,比如Jmetter wxk0248 发表于 2024-8-16 23:32
压测自己写不是很费劲么,为什么不用现成的,比如Jmetter
主要是要实时从接口获取代{过}{滤}理ip
页:
[1]
2