rust - UnixStream 的 read_to_end 方法永远不会返回
问题描述
我正在使用 Unix 域套接字来通信进程的应用程序中工作。为此,我使用标准库中的UnixListener
andUnixStream
类型。
我发现根据我读取数据的方式,进程可能会挂起。调试后我发现这取决于我是使用read
还是read_to_end
从套接字中检索数据。usingread
工作正常,而 usingread_to_end
使调用进程挂起,直到我杀死另一个进程(此时实际读取数据)。尽管文档没有提到任何类似的东西,但刷新缓冲区似乎是一个问题。
这是该问题的一个工作示例:
use std::env;
use std::io::{Read, Write};
use std::os::unix::net::{UnixListener, UnixStream};
use std::thread;
fn handle_client(mut stream: UnixStream) {
loop {
let mut read = [0; 1028];
match stream.read(&mut read) {
Ok(n) => {
if n == 0 {
// connection was closed
break;
}
let msg = String::from_utf8(read.to_vec()).unwrap();
println!("SERVER: {} received from remote client.", msg);
stream.write(&read[0..n]).unwrap();
}
Err(err) => {
panic!(err);
}
}
}
println!("SERVER: Ending connection with client.");
}
fn start_server(address: String) {
let listener = UnixListener::bind(&address).unwrap();
// accept connections and process them, spawning a new thread for each one
for connection in listener.incoming() {
match connection {
Ok(stream) => {
/* connection succeeded */
thread::spawn(|| handle_client(stream));
}
Err(err) => {
/* connection failed */
println!("Error connecting to client: {}", err);
break;
}
}
}
}
fn start_client(address: String, msg: String) {
let mut socket = match UnixStream::connect(&address) {
Ok(sock) => sock,
Err(e) => {
println!("Couldn't connect! {}.", e);
return;
}
};
let request = msg.into_bytes();
match socket.write_all(&request) {
Ok(_) => {}
Err(e) => println!("Error writing to socket: {}", e),
}
// This variant works
// let mut read = [0; 1028];
// match socket.read(&mut read) {
// This variant does not work.
let mut read = Vec::with_capacity(1024); //Comment this to make it work
match socket.read_to_end(&mut read) {
// Comment this to make it work
Ok(n) => {
if n == 0 {
// connection was closed
}
let msg = String::from_utf8(read.to_vec()).unwrap();
println!("CLIENT: {} received from server.", msg);
}
Err(err) => {
panic!(err);
}
}
}
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() > 2 {
let operation_mode = args[1].clone();
let address = args[2].clone();
if operation_mode == "server" {
start_server(address);
} else {
let msg = args[3].clone();
start_client(address, msg);
}
} else {
println!("not enough parameters");
}
}
要重现该问题,请像这样运行服务器进程:rm /tmp/sock & RUST_BACKTRACE=1 cargo run server /tmp/sock
然后像这样运行客户端进程:cargo run client /tmp/sock hello_world
问题重现时的预期输出是服务器进程按预期打印其输出:SERVER: hello_world received from remote client.
但客户端进程什么也不打印,直到服务器进程被杀死,此时它打印其预期输出:CLIENT: hello_world received from server.
要确认此问题已本地化到该read_to_end
方法,请取消注释标记为工作变体的行并注释标记为使示例正常工作的行。
这段代码有什么问题?我用read_to_end
错了吗?
解决方案
推荐阅读
- amazon-web-services - 在中国设置 gcp 或 aws k8s 集群的代理
- python - 基于用户输入的循环程序
- laravel - Helm:在 Job 中的其他容器上执行命令
- ios - 如何用单个标记多次点击
- arrays - 如何引用数组变量中的所有元素
- javascript - 函数名称,“onButtonClick”或“onClickButton”
- c - C指针不等于另一个
- list - 我的问题是关于在 Dart 中构建不断增长的多维列表(数组)的方法
- linux - 如何使用 linux shell 选择文件中不同列的内容?
- android - 应用未设置:此应用仍处于开发模式,Facebook UI 更改