C#如何实现多线程TCP服务端请求 解决单线程请求耗时过长问题
C# TCP并发请求代码调整方案
原有代码核心问题
- 方法定义为async void,外部无法等待执行完成,Main函数调用后会直接执行后续写文件、关闭连接逻辑,此时请求还未完成
- 单TcpClient实例多线程共享,NetworkStream非线程安全,并发读写会导致报文乱序、数据对应错误
- 循环内直接await Task.Run,所有任务串行执行,无法实现并发效果
- 数组索引越界风险:数组长度为2018,最大索引为2017,原逻辑i会遍历到2018,会触发索引越界异常
- 步长为5的循环逻辑错误,无法覆盖所有2018个数组位
调整后完整代码
using System; using System.IO; using System.Linq; using System.Net.Sockets; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; class Program { static int[] numList = new int[2018]; private const int Port = 替换为实际端口; private const string ServerIp = "替换为实际服务端IP"; // 预编译正则,提升匹配性能 private static readonly Regex NumRegex = new Regex(@"\d+", RegexOptions.Compiled); // 控制最大并发数为5 private static readonly SemaphoreSlim Semaphore = new SemaphoreSlim(5, 5); static async Task Main(string[] args) { // 生成所有需要请求的序号1-2018 var requestTasks = Enumerable.Range(1, 2018).Select(i => RequestSingle(i)); // 等待所有请求完成 await Task.WhenAll(requestTasks); // 排序数组计算中位数 Array.Sort(numList); double median; int len = numList.Length; if (len % 2 == 0) { median = (numList[len / 2 - 1] + numList[len / 2]) / 2.0; } else { median = numList[len / 2]; } Console.WriteLine($"中位数为:{median}"); // 写入文件 File.WriteAllLines("FileONE.txt", numList.Select(x => x.ToString())); Console.WriteLine("Запрос завершен..."); Console.ReadKey(); } /// <summary> /// 单次请求逻辑 /// </summary> private static async Task RequestSingle(int index) { // 等待并发许可 await Semaphore.WaitAsync(); try { // 每个请求用独立TcpClient,避免线程安全问题 using var client = new TcpClient(); await client.ConnectAsync(ServerIp, Port); using var stream = client.GetStream(); using var writer = new StreamWriter(stream) { AutoFlush = true }; using var reader = new StreamReader(stream); // 发送请求 await writer.WriteLineAsync(index.ToString()); // 接收响应 string message = await reader.ReadLineAsync(); // 提取数字 var match = NumRegex.Match(message); if (match.Success) { int result = Convert.ToInt32(match.Value); Console.WriteLine($"序号{index}请求结果:{result}"); // 数组索引从0开始,所以减1避免越界 numList[index - 1] = result; } } catch (Exception ex) { Console.WriteLine($"序号{index}请求失败:{ex.Message}"); // 可自行补充失败重试逻辑 } finally { // 释放并发许可 Semaphore.Release(); } } }
关键调整说明
- 用
SemaphoreSlim控制最大并发数为5,保证同时只有5个请求在执行 - 将异步方法返回值改为
Task,可通过Task.WhenAll等待所有请求完成后再执行后续逻辑 - 每个请求使用独立的
TcpClient实例,避免多线程共享连接导致的报文乱序问题 - 所有IO操作改为异步API(
ConnectAsync/WriteLineAsync/ReadLineAsync),提升资源利用率 - 修复数组索引问题,避免越界,覆盖所有2018个存储位
- 添加异常捕获逻辑,避免单个请求失败导致整个程序崩溃
注意事项
- 如果服务端支持同一连接多请求并行处理,可改为连接池复用TcpClient,减少连接建立开销
- 可在异常分支添加重试逻辑,提升请求成功率
- 本代码要求C#版本在7.1及以上,需在项目属性的「高级生成设置」中,将语言版本设置为7.1+,支持async Main
内容的提问来源于stack exchange,提问作者magrega
相关产品推荐
相关产品推荐

