variables - Rust 服务器必须保存变量的更新值

标签 variables server tcp rust

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

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

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

  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);
} 

最佳答案

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

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

那么,如何解决呢?

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

我们如何解决这个问题:对于第一部分,线程安全,我们可以使用 Mutex 。但这对于一个简单的整数来说有点过分了。我们使用原子。对于第二部分,我们可以使用 Arc - 我再次选择了更简单的选项,将其设为静态(“全局”)变量。
编辑:在评论中引起了我的注意,也许我对这个问题的“简单”解决方案的看法有点偏差,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 */
            }
        }
    }
}

关于variables - Rust 服务器必须保存变量的更新值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64305108/

相关文章:

c++ - 有关变量等函数的更多信息?

jquery - 客户端如何在不频繁ajax请求的情况下从服务器获取更新?

java - 我可以使用套接字列表发送给多个客户端吗?

tcp - Golang 1.5 io.Copy 用两个 TCPConn 阻塞

c - UDP recvfrom查询

java - TCP 服务器疯狂 - 缓慢且合并的数据

javascript - 在javascript中指定图像源

javascript - 如何将字符串和函数参数混合到一个变量中

javascript - 如果 JavaScript 是一种解释性语言,提升如何工作?

python-3.x - 为什么关闭与服务器的连接?