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

C#调用NetworkStream.ReadAsync报参数超出有效值范围错误求助

问题背景

非开发人员临时接手项目,遇到TCP通信报错,报错截图如下:
error message
经弹窗逐段调试,定位到报错触发代码段如下:

try
{
    String type = "I";
    String fullMessage = Convert.ToChar(1) + type + Convert.ToChar(2) + Convert.ToChar(3) + Convert.ToChar(13);
    NetworkStream serverStream = client.GetStream();
    byte[] outStream = Encoding.ASCII.GetBytes(fullMessage);
    serverStream.Write(outStream, 0, outStream.Length);
    serverStream.Flush(); ;
    
    byte[] inStream = new byte[10025];
    await serverStream.ReadAsync(inStream, 0, (int)client.ReceiveBufferSize);
    string returndata = System.Text.Encoding.ASCII.GetString(inStream);
    if (returndata.Length == 0)
    {
        MessageBox.Show("isError = true in try");
        isError = true;
        connected = false;
    }
}
catch (Exception e)
{
    MessageBox.Show(e.ToString());
    isError = true;
    connected = false;
}
错误原因

从截图报错信息(对应Socket错误码10054:远程主机强迫关闭现有连接),结合代码逻辑,触发原因按概率从高到低排列:

  • 发送的报文不符合服务端协议规范,服务端收到非法报文后直接主动断开连接。你构造的报文使用了SOH(0x01)、STX(0x02)、ETX(0x03)这类工业控制类协议常用的控制字符,这类协议对报文格式要求极严,目前你用单个回车符(0x0D)作为结尾,而绝大多数同类协议要求结尾必须是CRLF(0x0D 0x0A,即回车加换行),部分协议还要求附加校验字段,格式不对直接断连是这类服务端的通用处理逻辑。
  • 读取逻辑存在严重错误:ReadAsync方法的返回值是本次实际读到的字节数,返回0即代表服务端已经关闭连接。你现在完全没有接收这个返回值,直接把长度10025的完整缓冲区转成字符串,哪怕只读到1个字节,后面的10024个字节都是默认的\0空字符,既无法正确判断返回内容长度,后续解析也会出问题。另外你传入的读取长度是client.ReceiveBufferSize(默认值8192),虽然和初始化的10025长度缓冲区不会越界,但属于逻辑不严谨的写法。
  • 存在无效代码和缺失前置校验:NetworkStream是TCP流,不存在应用层缓冲区,Flush()方法对其完全无效,不会起到“立即发送数据”的作用;代码没有在读写前校验TcpClient的连接状态,半连接、已断开的情况下直接读写必然抛异常。
修复方案
  • 优先核对协议文档:找到项目里和服务端对接的协议说明,确认你构造的身份标识报文的控制字符顺序、结尾符、校验规则是否完全符合要求,这是解决10054错误的核心。
  • 修正网络流读写逻辑,修复后的完整代码如下:
try
{
    // 前置校验连接状态
    if (!client.Connected)
    {
        isError = true;
        connected = false;
        return;
    }

    string type = "I";
    // 注意:这里的结尾符请根据实际协议调整,示例为常见的CRLF结尾
    string fullMessage = Convert.ToChar(1) + type + Convert.ToChar(2) + Convert.ToChar(3) + "\r\n";
    NetworkStream serverStream = client.GetStream();
    byte[] outStream = Encoding.ASCII.GetBytes(fullMessage);
    serverStream.Write(outStream, 0, outStream.Length);

    byte[] inStream = new byte[client.ReceiveBufferSize];
    // 接收实际读取的字节数
    int actualReadLen = await serverStream.ReadAsync(inStream, 0, inStream.Length);
    // 读取长度为0即服务端正常关闭连接
    if (actualReadLen == 0)
    {
        MessageBox.Show("服务端已主动关闭连接");
        isError = true;
        connected = false;
        return;
    }
    // 只转换实际读到的字节段,避免空字符干扰
    string returndata = Encoding.ASCII.GetString(inStream, 0, actualReadLen);
    if (string.IsNullOrEmpty(returndata))
    {
        isError = true;
        connected = false;
    }
}
catch (IOException ioEx) when (ioEx.InnerException is SocketException { ErrorCode: 10054 })
{
    MessageBox.Show("连接被服务端强制断开,请优先检查发送的报文格式是否匹配协议要求");
    isError = true;
    connected = false;
}
catch (Exception e)
{
    MessageBox.Show(e.ToString());
    isError = true;
    connected = false;
}
  • 额外注意点:TCP是面向流的协议,ReadAsync不会保证一次读完服务端返回的所有数据,如果后续要处理长度更长的返回报文,需要循环读取直到读到协议约定的结束符或者达到约定报文长度,不能假设一次Read就能拿到完整数据。

内容的提问来源于stack exchange,提问作者KJ Work

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 14:03:20