You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 16:45:03