我需要实现TCP服务器,它存储一个变量M。一开始,M = 1。 但是,当服务器和客户端之间建立连接,并且客户端发送变量 N 的另一个值时,服务器下一步必须执行:M = M * N。并将该值返回给客户端。 服务器必须保存变量 M 的新值! 并且,当下一个新客户端设置连接时,它将使用变量的新值。 示例:
- 服务器:M = 1;客户端:N = 5;服务器:M = 5;
- 服务器:A = 5;客户端:N = 8;服务器:M = 40;
这是我的服务器代码。它以这种方式工作:(不保存新值(value)) 示例:
- 服务器:M = 1;客户端:N = 5;服务器:M = 5;
- 服务器: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/