浏览器接收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,浏览器无法解析这个非法的分块大小,因此直接关闭了连接。
修复步骤
- 修正1024字节块的分块大小:将
b"1024\r\n"替换为十六进制的b"400\r\n"(因为1024的十六进制是0x400)。 - 统一分块大小处理逻辑(推荐):把所有分块的大小都用十六进制格式化,避免重复代码和格式错误,简化后的读取分支如下:
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
相关产品推荐
相关产品推荐

