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

浏览器接收6个TCP分块数据后关闭连接,求原因及解决

TCP分块传输时浏览器提前关闭连接的问题排查

问题描述

我想用TCP分块传输图片、视频、音频,编写了如下Rust的send_chunked函数,但所有浏览器在仅接收少量分块(实际为6个1024字节块)后就关闭连接,报错“主机关闭连接(os error 10053)”。经测试,该文件应分为13个分块(11个1024字节块、1个296字节块、1个0字节结束块),请问浏览器对TCP连接的接收是否存在限制?连接关闭的原因是什么?

代码实现

fn send_chunked(req_path: String, mut stream: TcpStream) -> Result<()> {
        let mut f = fs::File::options().read(true).open(req_path).unwrap();
        let mut buf = [0; 1024];
        stream.write_all(b"HTTP/1.1 200 OK\r\nConnection: keep-alive\r\nTransfer-Encoding: chunked\r\n\r\n").unwrap();

        loop {
            match f.read(&mut buf[..]) {
                Ok(0) => {
                    println!("{:?}", &buf);
                    let eof_chunk = b"0\r\n\r\n";
                    stream.write_all(eof_chunk)?;
                    break;
                },
                Ok(1024) => {
                    println!("{:?}", &buf);
                    //println!("1024");
                    let chunk_size = b"1024\r\n";
                    stream.write_all(chunk_size)?;
                    let mut payload = Vec::with_capacity(1026);
                    payload.extend_from_slice(&buf);
                    payload.push(b'\r');
                    payload.push(b'\n');
                    stream.write_all(payload.as_slice())?;
                    buf.fill(0);
                },
                Ok(n) if n < 1024 => {
                    //println!("{}", &n);
                    let chunk_size = format!("{:x}\r\n", n as u64);
                    stream.write_all(chunk_size.as_bytes())?;
                    let mut payload = Vec::with_capacity(n + 2);
                    payload.extend_from_slice(&buf[..n]);
                    payload.push(b'\r');
                    payload.push(b'\n');
                    stream.write_all(payload.as_slice())?;
                }
                Err(e) => return Err(e),
                _ => (),
            }
        }
        
        Ok(())
    }

问题原因与解决方案

核心原因

浏览器本身没有这种固定的分块数量限制,连接提前关闭是因为分块大小格式不符合HTTP规范:
HTTP分块编码要求分块大小必须以十六进制表示,但你在处理1024字节的块时,直接发送了十进制的1024\r\n,浏览器无法解析这个非法的分块大小,因此直接关闭了连接。

修复步骤

  1. 修正1024字节块的分块大小:将b"1024\r\n"替换为十六进制的b"400\r\n"(因为1024的十六进制是0x400)。
  2. 统一分块大小处理逻辑(推荐):把所有分块的大小都用十六进制格式化,避免重复代码和格式错误,简化后的读取分支如下:
Ok(n) => {
    if n == 0 {
        let eof_chunk = b"0\r\n\r\n";
        stream.write_all(eof_chunk)?;
        break;
    }
    let chunk_size = format!("{:x}\r\n", n as u64);
    stream.write_all(chunk_size.as_bytes())?;
    let mut payload = Vec::with_capacity(n + 2);
    payload.extend_from_slice(&buf[..n]);
    payload.push(b'\r');
    payload.push(b'\n');
    stream.write_all(payload.as_slice())?;
    buf.fill(0);
}

这样不管读取到多少字节,都能生成符合规范的分块大小,浏览器可以正常解析所有分块,不会提前关闭连接。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 02:35:56