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

使用tokio::io::copy_bidirectional代理TCP连接时遇os error 107

使用Tokio实现TCP代理时遇到OS Error 107的问题

我需要基于socket2::Socket实现TCP连接代理,将其转换为tokio::net::TcpStream后,用Tokio的双向复制功能完成数据转发。整体功能看似正常——用curl发起HTTPS请求时,TLS握手能完成且能收到响应,但会触发os error 107 (Transport endpoint is not connected)错误,且预期的"bytes copied"日志从未出现。

初始实现代码

let std_stream: std::net::TcpStream = socket.into();
std_stream.set_nonblocking(true)?;
let mut inbound = TcpStream::from_std(std_stream)?;
debug!("created inbound tcp stream from socket");

tokio::spawn(async move {
    match TcpStream::connect(&dest_addr).await {
        Ok(mut outbound) => {
            debug!("connected to {dest_addr}");

            match tokio::io::copy_bidirectional(&mut inbound, &mut outbound).await {
                Ok((nsent, nrcvd)) => {
                    debug!(sent_bytes = nsent, rcvd_bytes = nrcvd, "bytes copied");
                    return Ok(());
                }

                Err(err) => {
                    error!(
                        "💥️ — proxying for address {} failed: {}",
                        &dest_addr, err
                    );
                    return Err(err);
                }
            }
        }
        Err(err) => {
            error!(
                "unable to connect to downstream host {:?}: {err}",
                dest_addr
            );

            return Err(err);
        }
    }
});

错误日志

{"timestamp":"2024-04-15T17:33:56.042465Z","level":"DEBUG","fields":{"message":"created inbound tcp stream from socket"},"target":"tfw"}
{"timestamp":"2024-04-15T17:33:56.080270Z","level":"DEBUG","fields":{"message":"connected to 104.244.42.129:443"},"target":"tfw"}
{"timestamp":"2024-04-15T17:33:56.342300Z","level":"ERROR","fields":{"message":"💥️ — proxying for address 104.244.42.129:443 failed: Transport endpoint is not connected (os error 107)"},"target":"tfw"}

排查过程更新

4/16/24 10:00 更新:自行实现双向复制逻辑

我替换了Tokio内置的copy_bidirectional,改用自定义的双向复制逻辑:

/// Runs the actual proxying of a socket.
async fn transfer(mut incoming: TcpStream, mut outbound: TcpStream) -> Result<(), std::io::Error> {
    // Split the streams into read and write halves.
    let (mut read_inbound, mut write_inbound) = incoming.split();
    let (mut read_outbound, mut write_outbound) = outbound.split();

    // Forward client data to server
    let client_to_server = async {
        tokio::io::copy(&mut read_inbound, &mut write_outbound)
            .await
            .inspect_err(|e| {
                error!(
                    error = e.to_string(),
                    "error copying read_inbound to write_outbound!"
                )
            })?;

        debug!("finished copying read_inbound to write_outbound, shutting down write_outbound");
        write_outbound
            .shutdown()
            .await
            .inspect_err(|e| error!(error = e.to_string(), "error shutting down write_outbound!"))
    };

    // Forward server data to client
    let server_to_client = async {
        tokio::io::copy(&mut read_outbound, &mut write_inbound)
            .await
            .inspect_err(|e| {
                error!(
                    error = e.to_string(),
                    "error copying read_outbound to write_inbound!"
                )
            })?;

        debug!("finished copying read_outbound to write_inbound, shutting down write_inbound");
        write_inbound
            .shutdown()
            .await
            .inspect_err(|e| error!(error = e.to_string(), "error shutting down write_inbound!"))
    };

    // Poll both tasks.
    tokio::try_join!(client_to_server, server_to_client)?;

    Ok(())
}

测试后仍会触发错误,但日志显示错误发生在所有数据复制完成后、关闭write_inbound时,关闭write_outbound则无异常。我推测是curl客户端提前关闭了连接,导致inbound流已处于关闭状态,此时手动执行关闭操作就会触发错误。

4/16/24 10:20 更新:移除write_outbound关闭操作后的验证

我移除了write_outbound的关闭逻辑,测试是否关闭一个流会影响另一个,但错误依然在关闭write_inbound时触发,进一步确认是客户端已提前关闭该连接,导致后续手动关闭操作报错。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 14:47:12