【问题标题】:Rust server must save the updated value of variableRust 服务器必须保存变量的更新值
【发布时间】:2021-01-26 00:20:59
【问题描述】:

我需要实现TCP服务器,它存储一个变量M。开始时,M = 1。 但是,当服务器和客户端之间建立连接时,客户端发送另一个变量 N 的值,服务器必须执行下一步:M = M * N。并将该值返回给客户端。 服务器必须保存变量 M 的新值! 并且,当下一个新客户端设置连接时,它将使用新的变量值。 示例:

  1. 服务器:M = 1;客户:N = 5;服务器:M = 5;
  2. 服务器:A = 5;客户:N = 8;服务器:M = 40;

这是我的服务器代码。它以这种方式工作:(不保存新值) 示例:

  1. 服务器:M = 1;客户:N = 5;服务器:M = 5;
  2. 服务器:A = 1;客户:N = 8;服务器:M = 8;

也许我应该做一个全局变量?或者关于它的东西......给我一些建议。谢谢。

fn handle_client(mut stream: TcpStream, a:&mut i32) {
    let mut data = [0 as u8; 30]; // using 30 byte buffer
    
    while match stream.read(&mut data) {
    
        Ok(size) => {
           if size>0{
           
           let temp = str::from_utf8(&data[0..size]).unwrap().to_string();
                        
           let temp: i32  = temp.trim().parse().unwrap();                  
           
            *a = *a * temp;
                  
            let st = a.to_string();
            // String в u8
            let data = st.as_bytes();
            

            stream.write(&data).unwrap();
           }
            true
        },
        Err(_) => {
            println!("An error occurred, terminating connection with {}", stream.peer_addr().unwrap());
            stream.shutdown(Shutdown::Both).unwrap();
            false
        }
    } {}
}


fn main() {
    let listener = TcpListener::bind("0.0.0.0:7956").unwrap();
    
   let mut a: i32 = 1;
    // accept connections and process them, spawning a new thread for each one
    println!("Server listening on port 7956");
    println!("A = 1");
    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                println!("New connection: {}", stream.peer_addr().unwrap());
                thread::spawn(move|| {
                    // connection succeeded
                    handle_client(stream, &mut a)
                });
            }
            Err(e) => {
                println!("Error: {}", e);
                /* connection failed */
            }
        }
    }
    // close the socket server
    drop(listener);
} 

【问题讨论】:

    标签: variables server tcp rust


    【解决方案1】:

    为什么您的代码不起作用?

    因为您将a 移动到闭包中,从而复制了它。为了做到这一点,你只需要问:你需要什么才能进入闭包,这样&mut a 的类型是&mut i32
    确切地说,一个“原始”i32。编译器是如何做到的?通过复制它。这意味着对闭包“内部”变量的更改不会反映在“外部”。

    嗯,那怎么解决呢?

    让我们从头开始:如果你只是在调用中不借用,你会将可变引用移动到闭包中——但这不起作用,原因有两个:首先,它显然不是线程安全的,其次,借用的生命周期甚至不能保证足够长('static)。

    我们如何解决这个问题:对于第一部分,线程安全,我们可以使用Mutex。不过,这对于一个简单的整数来说太过分了。我们使用原子。对于第二部分,我们可以使用 Arc - 我再次选择了更简单的选项,将其设为静态(“全局”)变量。
    编辑:在 cmets 中它被提出引起我的注意,也许我对这个问题的“简单”解决方案的看法有点偏颇,this 是本书中线程安全章节的链接,它使用Arc<Mutex<_>> 数到十平行线。每个 Rust 程序员都应该阅读该部分(以及整本书!)。

    这是你的代码,只重写了相关部分:

    use std::sync::atomic;
    
    fn handle_client(mut stream: TcpStream) {
        let mut data = [0 as u8; 30]; // using 30 byte buffer
    
        while match stream.read(&mut data) {
            Ok(size) => {
                if size > 0 {
                    let temp = std::str::from_utf8(&data[0..size]).unwrap().to_string();
    
                    let temp: i32 = temp.trim().parse().unwrap();
    
                    let prev_a_val = loop {
                        let a_acquired = a.load(atomic::Ordering::Acquire);
                        match a.compare_exchange_weak(
                            a_acquired,
                            a_acquired * temp,
                            atomic::Ordering::AcqRel,
                            atomic::Ordering::Acquire,
                        ) {
                            Ok(value) => break value,
                            Err(_) => {}
                        }
                    };
    
                    let st = (prev_a_val * temp).to_string();
                    // String в u8
                    let data = st.as_bytes();
    
                    stream.write(&data).unwrap();
                }
                true
            }
            Err(_) => {
                println!(
                    "An error occurred, terminating connection with {}",
                    stream.peer_addr().unwrap()
                );
                stream.shutdown(Shutdown::Both).unwrap();
                false
            }
        } {}
    }
    
    static a: atomic::AtomicI32 = atomic::AtomicI32::new(1);
    
    fn main() {
        let listener = TcpListener::bind("0.0.0.0:7956").unwrap();
    
        // accept connections and process them, spawning a new thread for each one
        println!("Server listening on port 7956");
        println!("A = 1");
        for stream in listener.incoming() {
            match stream {
                Ok(stream) => {
                    println!("New connection: {}", stream.peer_addr().unwrap());
                    thread::spawn(|| {
                        // connection succeeded
                        handle_client(stream)
                    });
                }
                Err(e) => {
                    println!("Error: {}", e);
                    /* connection failed */
                }
            }
        }
    }
    

    【讨论】:

    • 这似乎可行,但我个人更愿意将Arc<Mutex<i32>> 传递给处理程序。这种方式没有排序奥秘,也没有全局变量。
    • @NovaDenizen 这并不是说您没有使用互斥锁的订单,它只是对您隐藏。从教学的角度来看,Arc<Mutex<_>> 可能更有意义,但我不是老师,我是一名专注于 HPC 的开发人员。我不会用锯子来拧螺丝。
    • 奇怪的是,我们对什么是“矫枉过正”和什么是“简单”的看法在这里截然相反。
    猜你喜欢
    • 2012-08-24
    • 2021-05-30
    • 1970-01-01
    • 2017-05-21
    • 2018-09-10
    • 2020-10-01
    • 2022-01-25
    • 2016-06-06
    • 2023-03-16
    相关资源
    最近更新 更多