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

从零实现Rust WebSocket客户端遇连接升级响应问题求助

从零实现Rust WebSocket客户端的连接问题解决

问题现象

  • 作为Rust新手,从零实现WebSocket客户端时,连接echo.websocket.org等回声服务器始终无法获取升级响应。
  • 移除请求头中的Upgrade: websocket字段后,能收到200响应,说明服务器可达且底层Socket通信正常。
  • 尝试多个WebSocket回声服务器均不认可请求头;Postman可正常连接目标服务器,但复制其请求头仍无法解决问题。

排查与解决过程

  • 先按照建议将base64随机数(nonce)的生成方式更新为与tungstenite一致的实现(引入data-encoding依赖),但问题未解决。
  • 最终定位核心问题:原代码使用read_to_string等待EOF,但WebSocket服务器不会发送EOF,必须按\r\n逐行读取响应。改用tokio的BufReader处理输入流后,问题得到解决。

初始代码

use std::sync::Arc;
use rand::Rng;
use rustls::{pki_types::ServerName, ClientConfig, RootCertStore};
use tokio::{io::{AsyncReadExt, AsyncWriteExt}, net::{lookup_host, TcpSocket}};
use tokio_rustls::TlsConnector;

#[tokio::main]
async fn main() {
    let nonce = generate_nonce();
    let host = "echo.websocket.org";
    let port = 443;
    let path = "/";
    let addr = format!("{}:{}", host, port);
    let addr = lookup_host(addr).await.unwrap().next().unwrap();
    let socket = TcpSocket::new_v4().unwrap();
    let mut stream = socket.connect(addr).await.unwrap();
    let server_name = ServerName::try_from(host).unwrap();
    let mut tls = get_tls_connector().connect(server_name, &mut stream).await.unwrap();
    let mut write_string = String::new();
    write_string.push_str(format!("GET {} HTTP/1.1\r\n", path).as_str());
    write_string.push_str(format!("Host: {}\r\n", host).as_str());
    write_string.push_str("Connection: Upgrade\r\n");
    write_string.push_str("Upgrade: websocket\r\n");
    write_string.push_str(format!("Sec-WebSocket-Key: {}\r\n", nonce).as_str());
    write_string.push_str("Sec-WebSocket-Version: 13\r\n");
    write_string.push_str("\r\n");
    tls.write_all(write_string.as_bytes()).await.unwrap();
    tls.flush().await.unwrap();
    let mut read_str = String::new();
    let _size = tls.read_to_string(&mut read_str).await.unwrap();
    println!("{}", read_str);
    read_str.clear();
}

fn generate_nonce() -> String {
    let r: [u8; 16] = rand::random();
    data_encoding::BASE64.encode(&r)
}

fn get_tls_connector() -> TlsConnector {
    let mut root_store = RootCertStore::empty();
    root_store.extend(webpki_roots::TLS_SERVER_ROOTS
    .iter()
    .cloned()
    );
    let config = ClientConfig::builder()
    .with_root_certificates(root_store)
    .with_no_client_auth();
    let rc_config = Arc::new(config);
    TlsConnector::from(rc_config)
}

修改后的main函数

use std::sync::Arc;

use rustls::{pki_types::ServerName, ClientConfig, RootCertStore};
use tokio::{io::{split, AsyncBufReadExt, AsyncWriteExt, BufReader}, net::{lookup_host, TcpSocket}};
use tokio_rustls::TlsConnector;


#[tokio::main]
async fn main() {
    let nonce = generate_nonce();
    let host = "echo.websocket.org";
    let port = 443;
    let path = "/";
    let addr = format!("{}:{}", host, port);
    let addr = lookup_host(addr).await.unwrap().next().unwrap();
    let socket = TcpSocket::new_v4().unwrap();
    let mut stream = socket.connect(addr).await.unwrap();
    let server_name = ServerName::try_from(host).unwrap();
    let tls = get_tls_connector().connect(server_name, &mut stream).await.unwrap();
    let (reader, mut writer) = split(tls);
    let mut write_string = String::new();
    write_string.push_str(format!("GET {} HTTP/1.1\r\n", path).as_str());
    write_string.push_str(format!("Host: {}\r\n", host).as_str());
    write_string.push_str("Connection: Upgrade\r\n");
    write_string.push_str("Upgrade: websocket\r\n");
    write_string.push_str(format!("Sec-WebSocket-Key: {}\r\n", nonce).as_str());
    write_string.push_str("Sec-WebSocket-Version: 13\r\n");
    //write_string.push_str("Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n");
    write_string.push_str("\r\n");
    writer.write_all(write_string.as_bytes()).await.unwrap();
    writer.flush().await.unwrap();
    let mut lines = BufReader::new(reader).lines();
    loop {
        let line = lines.next_line().await.unwrap().unwrap();
        println!("{}", line);
        if line.is_empty() {
            break;
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:25:55