为什么我的 QUIC 连接无法交换数据,而 TCP 在 Rust 中工作正常?

问题描述 投票:0回答:1

我正在用 Rust 开发一个通信层,它支持 TCP 和 QUIC 协议,用于客户端和服务器之间的数据交换。 TCP 实现工作完美,但 QUIC 设置在数据传输方面遇到问题,尽管连接成功。完整代码

设置和执行命令

使用以下命令在 TCP 和 QUIC 模式下测试设置:

  • TCP 监听器
    cargo run -- listener tcp
  • TCP 客户端
    cargo run -- conn tcp
  • QUIC 监听器
    cargo run -- listener quic
  • QUIC 客户端
    cargo run -- conn quic

观察到的行为

TCP 模式(工作正常)

  • TCP监听器:服务器启动成功,并正常接收客户端数据。
  • TCP Client:客户端连接成功,并与服务器端交互消息。

输出示例:

  • TCP 侦听器输出:

    Running as tcp listener on 127.0.0.1:5000
    Tcp listener started at 127.0.0.1:46220
    Received from client: [72, 101, 108, 108, 111, 32, 102, 114, 111, 109, 32, 99, 108, 105, 101, 110, 116]
    
  • TCP 客户端输出:

    Running as tcp client connecting to 127.0.0.1:5000
    Received from server: [72, 101, 108, 108, 111, 32, 102, 114, 111, 109, 32, 115, 101, 114, 118, 101, 114]
    

QUIC模式(数据传输问题)

  • QUIC Listener:服务器启动、监听并成功接受来自客户端的连接,但没有收到任何有意义的数据。相反,它显示一个空数组
    []
  • QUIC 客户端:客户端连接无错误,但没有数据交换。

输出示例:

  • QUIC 监听器输出:

    QUIC server started on 127.0.0.1:5000
    Running as quic listener on 127.0.0.1:5000
    Connection received from 127.0.0.1:6000
    Received from client: []
    
  • QUIC 客户端输出:

    Attempting to connect to server at 127.0.0.1:5000
    Connected to server
    

关注要点

  1. Connection Success without Data Exchange:QUIC 客户端和监听器成功建立连接,但没有交换实际数据。
  2. 收到空数据:QUIC 侦听器显示空消息 (
    []
    ),表明存在传输或接收问题。
  3. 工作 TCP 实现:由于 TCP 工作正常,这表明消息处理的设置可能是正确的,并且问题可能特定于 QUIC 流处理。

相关代码片段

以下是

Listener
Conn
和 QUIC 实现的一些相关代码片段。

Conn
Listener

的特征定义
use async_trait::async_trait;
use std::error::Error;

#[async_trait]
pub trait Conn {
    async fn send(&mut self, data: &[u8]) -> Result<(), Box<dyn Error + Send + Sync>>;
    async fn receive(&mut self) -> Result<Vec<u8>, Box<dyn Error + Send + Sync>>;
}

#[async_trait]
pub trait Listener {
    async fn accept(&self) -> Result<Box<dyn Conn + Send + Sync>, Box<dyn Error + Send + Sync>>;
}

QuicListen
实施

use quinn::{Endpoint, ServerConfig};
use rustls::pki_types::{CertificateDer, PrivatePkcs8KeyDer};
use std::{error::Error, fs, net::SocketAddr, sync::Arc};
use tokio::io::AsyncReadExt;
use crate::conn::Conn;
use crate::listener::Listener;

pub struct QuicListen {
    pub(crate) endpoint: Endpoint,
}

#[async_trait::async_trait]
impl Listener for QuicListen {
    async fn accept(&self) -> Result<Box<dyn Conn + Send + Sync>, Box<dyn Error + Send + Sync>> {
        let conn = self.endpoint.accept().await;
        let connection = conn.unwrap().await?;
        println!("Connection received from {:?}", connection.remote_address());
        let connection_clone = connection.clone();

        // Accept a unidirectional receive stream
        tokio::spawn(async move {
            if let Ok(mut recv_stream) = connection_clone.accept_uni().await {
                println!("Accepted unidirectional stream"); // Debug statement
                let mut buffer = [0; 1024];
                match recv_stream.read(&mut buffer).await {
                    Ok(Some(n)) => {
                        println!("Received message from client: {:?}", &buffer[..n]);
                    }
                    Ok(None) => println!("Client closed the stream"),
                    Err(e) => eprintln!("Error receiving message: {:?}", e),
                }
            } else {
                eprintln!("Failed to accept unidirectional stream");
            }
        });

        Ok(Box::new(QuicDummyConn {
            connection,
        }))
    }
}

QuicConn
实施

use std::{error::Error, fs, net::SocketAddr, sync::Arc};
use quinn::{ClientConfig, Connection as QuicConnection, Endpoint, RecvStream, SendStream};
use rustls::pki_types::CertificateDer;
use crate::conn::Conn;
use tokio::io::AsyncReadExt;

pub struct QuicConn {
    pub(crate) connection: QuicConnection,
    pub(crate) send_stream: SendStream,
}

#[async_trait]
impl Conn for QuicConn {
    async fn send(&mut self, data: &[u8]) -> Result<(), Box<dyn Error + Send + Sync>> {
        println!("Sending from quic connection");
        self.send_stream.write_all(data).await?;
        Ok(())
    }

    async fn receive(&mut self) -> Result<Vec<u8>, Box<dyn Error + Send + Sync>> {
        let mut buffer = vec![0; 1024];
        match self.recv_stream.read(&mut buffer).await? {
            Some(n) => {
                buffer.truncate(n);
                Ok(buffer)
            }
            None => Err("Stream closed".into()),
        }
    }
}

综上所述,TCP 正常工作,而 QUIC 无法传输数据。我希望得到有关解决 QUIC 空数据问题的任何指导,特别是围绕 QUIC 的流处理或可能的数据刷新要求的指导。谢谢!

  1. 测试 TCP 和 QUIC 模式:

    • 我设置服务器来处理 TCP 和 QUIC 模式的连接和数据交换。 TCP 模式按预期工作,客户端成功发送和接收来自服务器的消息。
  2. 调试QUIC连接和数据交换:

    • 对于 QUIC 实现,我通过检查服务器端的“Connection returned”来确保客户端和服务器建立连接。这证实了 QUIC 连接已成功建立。
    • 我添加了调试语句来监控从客户端发送到服务器接收的数据,结果显示一条空消息(
      []
      ),表明数据没有正确传输。
  3. 验证数据发送和流关闭:

    • 我确保在 QUIC 发送流上调用
      write_all
      ,并尝试在客户端使用
      finish().await?
      关闭流,以确保数据刷新到服务器。

我所期待的

我预计 QUIC 实现的行为与 TCP 实现类似,其中:

  • 客户端连接到服务器。
  • 客户端向服务器发送消息,服务器接收完整消息。

在 QUIC 模式下,服务器正确接收连接,但始终读取空消息,即使客户端指示已发送数据。我期望服务器接收到与 TCP 模式下成功发送和接收的消息内容相同的消息。 完整代码

rust udp rust-tokio udpclient quic
1个回答
0
投票

您的完整代码中存在一个错误

transport_config.max_concurrent_uni_streams(0_u8.into());

这将阻止打开任何单向流,例如客户端尝试打开的流

let send_stream = connection.open_uni().await?;

如果您仍然遇到问题,请将限制提高到 1 并更新您的问题。

© www.soinside.com 2019 - 2024. All rights reserved.