首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >正确的2个TcpStream

正确的2个TcpStream
EN

Stack Overflow用户
提问于 2021-10-28 22:05:36
回答 1查看 38关注 0票数 0

我在一个TCP代理服务器上工作,其中一个客户端连接到它,它启动一个到后端的新连接,并转发所有数据包(双向)。处理这一部分的函数如下所示。

代码语言:javascript
复制
pub fn route(source: TcpStream, worker: Worker) -> Result<()> {
    // `source` and `destination` are both `TcpStream`
    let mut source = source;
    let mut destination = TcpStream::connect(worker.address)?;

    let mut source_copy = source.try_clone()?;
    let mut destination_copy = destination.try_clone()?;
    let src2dst = std::thread::spawn(move || {
        std::io::copy(&mut source_copy, &mut destination_copy).unwrap();
    });

    let dst2src = std::thread::spawn(move || {
        std::io::copy(&mut destination, &mut source).unwrap();
        // source.shutdown(Shutdown::Both).unwrap(); <--- if this line is commented, it will stuck
    });

    src2dst.join().unwrap();
    dst2src.join().unwrap();
    Ok(())
}

但是,在其当前形式中,此函数将被卡住。特别是,如果我在destination停止写入时关闭了source,它就不会阻塞。但是我仍然不确定为什么它能工作(或者为什么它不能)。我目前只使用它来代理HTTP流量,并且它似乎没有问题。但我不确定它是否适用于通用TCP。这样做的正确方法是什么?

EN

回答 1

Stack Overflow用户

发布于 2021-10-28 22:53:31

std::io::copy从读取器读取,直到它获得文件结束条件。在TCP连接上发出文件结束状态的信号的方法是发送一个FIN包,这是通过调用shutdown关闭连接的写半部分在软件中实现的。

HTTP允许重用单个连接来逐个发送多个请求。请求中有足够的信息供接收方确定请求的结束位置,同样,响应也有足够的信息。在你的例子中,后端似乎关闭了它的写连接,这会导致你的io::copy返回。如果超文本传输协议响应的报头中有Connection: close,那么您必须关闭写半部分,否则客户端将挂起等待响应体,因为它从未接收到FIN数据包。

TL;DR:当A到B的拷贝正常返回时,您应该关闭B的写半部分,以转发文件末尾状态(FIN数据包)。这适用于两个方向的副本,并且通常对TCP有效。关闭读的那一半套接字似乎没有必要(它不会生成任何TCP数据包)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69761475

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档