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

.NET 6 WinForm发送32KB字节数组至REST API失败问题排查

在.NET 6 WinForm中发送32KB固件分块数据包失败的解决方法

问题描述

我尝试将固件文件以字节数组形式分块发送至REST API,JavaScript中可正常发送32KB数据包,但在.NET 6 WinForm中仅能发送2KB数据包,超过该大小就会失败。已查看Wireshark日志未发现异常,不清楚数据包去向。以下是报错信息及相关代码,求问如何在.NET中将数据包大小调整为32KB?

报错信息:

System.Net.WebException
  HResult=0x80131620
  Message=An error occurred while sending the request.
  Source=System.Net.Requests

Inner Exception 1:
HttpRequestException: An error occurred while sending the request.

Inner Exception 2:
IOException: Unable to read data from the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond..

Inner Exception 3:
SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

相关代码:

public void fnUpdateFirmware()
{
    bool blnUpdateDone = false;
    #region Initialize FW Update Call

    // filePath = "D:\\Work\\BitBucket_Projects\\LMS_2.1.0\\Working\\lion-management-suite\\solutions\\LioN Management Suite V2\\src\\bin\\Debug\\firmwares\\935708001\\V11.1.4.16\\dig_light_8dido_mp.fwu";
    Data = File.ReadAllBytes(filePath);

    data = "size=" + Data.Length;
    array1 = Encoding.ASCII.GetBytes(data);
    uri = new Uri(http + DeviceIp + fwupdate);//"http://192.168.1.10/fwup_install"
    httpSend.uri = uri;
    httpSend.DigestAuth = true;
    httpSend.method = "POST";
    httpSend.username = UName;// "admin";
    httpSend.password = Pwd;// "private";
    httpSend.senddata = array1;
    httpSend.contentType = "text/plain";

    //Start = false;
    fnUpdateCallAuthentication(ref httpSend);
    // textBox1.Text = "Device Initialize Successfully !";

    #endregion

    #region Firmware Update 

    //filePath = "D:\\Work\\BitBucket_Projects\\LMS_2.1.0\\Working\\lion-management-suite\\solutions\\LioN Management Suite V2\\src\\bin\\Debug\\firmwares\\935708001\\V11.1.4.16\\dig_light_8dido_mp.fwu";
    Data = File.ReadAllBytes(filePath);
    int sendbytes = 0;
    int Var = 1024*2;
    int Len = Convert.ToInt32(Data.Length / Var);
    int Counter = 0;
    //HttpSendDataReq httpSend = new HttpSendDataReq();

    while (Data.Length > sendbytes)
    {
        if (Counter < Len)
        {
            array1 = new byte[Var];

            for (int i = 0; i < array1.Length; i++)
            {
                if (sendbytes < Data.Length)
                {
                    array1[i] = Data[sendbytes];
                    sendbytes++;
                }
                else
                {
                    break;
                }
            }
            Counter++;
            // textBox1.Text = Counter.ToString();
        }
        else
        {

            array1 = new byte[Data.Length - (Var * Len)];
            //textBox1.Text += "Remaining Array Length = " + array1.Length.ToString();
            for (int i = 0; i < array1.Length; i++)
            {
                array1[i] = Data[sendbytes];
                sendbytes++;
            }
        }


        uri = new Uri(http + DeviceIp + fwupdate);
        httpSend.uri = uri;
        httpSend.DigestAuth = true;
        httpSend.method = "POST";
        httpSend.username = UName;// "admin";
        httpSend.password = Pwd;// "private";
        httpSend.senddata = array1;
        httpSend.contentType = "application/octet-stream";
        // Start = false;
        fnUpdateCallAuthentication(ref httpSend);
    }
    //textBox1.Text += "\n Firmware file sent successfully !";
    #endregion


    //return blnUpdateDone;
}


private string fnUpdateCallAuthentication(ref HttpSendDataReq sendData)
{
    try
    {
        // AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
        // HttpWebRequest webRequest = (HttpWebRequest)base.GetWebRequest(uri);
        // HttpClient httpClient = Htt
        WebRequest myWebRequest = HttpWebRequest.Create(sendData.uri);

        HttpWebRequest myHttpWebRequest = (HttpWebRequest)myWebRequest;

        NetworkCredential myNetworkCredential = new NetworkCredential(sendData.username, sendData.password);

        CredentialCache myCredentialCache = new CredentialCache();
        myCredentialCache.Add(sendData.uri, "Digest", myNetworkCredential);

        myHttpWebRequest.PreAuthenticate = true;
        myHttpWebRequest.Credentials = myCredentialCache;

        if (sendData.method.ToLower() == "post")
        {
            myHttpWebRequest.Method = sendData.method;
            myHttpWebRequest.KeepAlive = false;
            myHttpWebRequest.ContentType = sendData.contentType;
            if (null == sendData.senddata)
            {
                myHttpWebRequest.ContentLength = sendData.senddata.Length;


                StreamWriter requestWriter = new StreamWriter(myHttpWebRequest.GetRequestStream());
                requestWriter.Write(sendData.sendraw);
                requestWriter.Close();
                requestWriter = null;
            }
            else
            {
                Stream requestStream = myHttpWebRequest.GetRequestStream();
                requestStream.Write(sendData.senddata, 0, sendData.senddata.Length);
                requestStream.Close();
            }
        }

        using (WebResponse myWebResponse = myWebRequest.GetResponse())
        {

            Stream responseStream = myWebResponse.GetResponseStream();
            sendData.response = responseStream;

            StreamReader myStreamReader = new StreamReader(responseStream, Encoding.Default);

            string pageContent = myStreamReader.ReadToEnd();
            sendData.resstring = pageContent;

            responseStream.Close();

            myWebResponse.Close();
            // Console.WriteLine(pageContent);
            if (pageContent.Contains("FWUP_STATE_RDY4RST"))
            {
                // textBox1.Text += pageContent;
                start = true;
            }
            return pageContent;

        }

    }
    catch (Exception e)
    {
        // textBox2.Text += e.Message;
        return null;
    }


}

解决方案

1. 调整分块大小并修复分块逻辑

将分块大小从1024*2改为1024*32,同时修复原代码中计算分块数量的误差(原代码用整数除法会丢失余数部分的分块)。简化后的分块逻辑如下:

int chunkSize = 1024 * 32; // 设置为32KB分块
int totalChunks = (int)Math.Ceiling((double)Data.Length / chunkSize);
int sendBytes = 0;

for (int chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++)
{
    int currentChunkSize = Math.Min(chunkSize, Data.Length - sendBytes);
    byte[] chunk = new byte[currentChunkSize];
    Array.Copy(Data, sendBytes, chunk, 0, currentChunkSize);
    sendBytes += currentChunkSize;

    // 发送当前分块
    uri = new Uri(http + DeviceIp + fwupdate);
    httpSend.uri = uri;
    httpSend.DigestAuth = true;
    httpSend.method = "POST";
    httpSend.username = UName;
    httpSend.password = Pwd;
    httpSend.senddata = chunk;
    httpSend.contentType = "application/octet-stream";
    fnUpdateCallAuthentication(ref httpSend);
}

2. 优化HttpWebRequest配置

原代码中HttpWebRequest的配置存在缺失,补充以下配置解决大请求超时或发送失败问题:

// 在fnUpdateCallAuthentication方法中添加
myHttpWebRequest.Timeout = 30000; // 设置30秒超时,按需调整
myHttpWebRequest.ReadWriteTimeout = 30000;
myHttpWebRequest.AllowWriteStreamBuffering = false; // 禁用缓冲,直接发送数据
myHttpWebRequest.ContentLength = sendData.senddata.Length; // 显式设置ContentLength,原代码逻辑有误需修正

注意:原代码中if (null == sendData.senddata)分支存在空指针风险,需调整该分支逻辑,避免在senddata为null时访问其Length属性。

3. 改用HttpClient替代HttpWebRequest

HttpWebRequest是较旧的API,HttpClient在.NET 6+中更稳定且易于配置,适合大请求发送。示例代码如下:

// 建议全局单例初始化HttpClient
private static readonly HttpClient _httpClient = new HttpClient();

private async Task<string> SendChunkAsync(byte[] chunk, Uri uri, string username, string password)
{
    var credential = new NetworkCredential(username, password);
    var cache = new CredentialCache {{ uri, "Digest", credential }};
    _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Digest", cache.GetCredential(uri, "Digest").ToString());

    using var content = new ByteArrayContent(chunk);
    content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
    var response = await _httpClient.PostAsync(uri, content);
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadAsStringAsync();
}

调用该方法发送32KB分块即可,HttpClient会自动处理连接和超时配置,减少手动出错概率。

4. 检查服务器端配置

对比Wireshark中JavaScript和.NET发送的请求,确保请求头、认证信息完全一致。部分服务器可能对不同客户端的请求有特殊限制,需确认服务器端是否允许.NET客户端发送32KB大小的请求。

内容的提问来源于stack exchange,提问作者Aditya Desai

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 21:30:56