73、[练习]客户端进阶
专有Client类型
客户端的所有交互都相当低级:我们必须手动建立一个响应通道,建立命令,将其发送到服务器,然后在响应通道上调用 recv 来获取响应。
这是大量可以抽象掉的模板代码,而这正是我们在本练习中要做的。
练习
use crate::data::{Ticket, TicketDraft};
use crate::store::{TicketId, TicketStore};
use std::sync::mpsc::{Receiver, Sender};
pub mod data;
pub mod store;
#[derive(Clone)]
// TODO: flesh out the client implementation.
pub struct TicketStoreClient {
sender: Sender<Command>,
}
impl TicketStoreClient {
// Feel free to panic on all errors, for simplicity.
pub fn insert(&self, draft: TicketDraft) -> TicketId {
/* TODO */
}
pub fn get(&self, id: TicketId) -> Option<Ticket> {
/* TODO */
}
}
pub fn launch() -> TicketStoreClient {
let (sender, receiver) = std::sync::mpsc::channel();
std::thread::spawn(move || server(receiver));
/* TODO */
}
// No longer public! This becomes an internal detail of the library now.
enum Command {
Insert {
draft: TicketDraft,
response_channel: Sender<TicketId>,
},
Get {
id: TicketId,
response_channel: Sender<Option<Ticket>>,
},
}
fn server(receiver: Receiver<Command>) {
let mut store = TicketStore::new();
loop {
match receiver.recv() {
Ok(Command::Insert {
draft,
response_channel,
}) => {
let id = store.add_ticket(draft);
let _ = response_channel.send(id);
}
Ok(Command::Get {
id,
response_channel,
}) => {
let ticket = store.get(id);
let _ = response_channel.send(ticket.cloned());
}
Err(_) => {
// There are no more senders, so we can safely break
// and shut down the server.
break;
}
}
}
}
use crate::data::{Ticket, TicketDraft};
use crate::store::{TicketId, TicketStore};
use std::sync::mpsc::{Receiver, Sender};
pub mod data;
pub mod store;
#[derive(Clone)]
// TODO: flesh out the client implementation.
pub struct TicketStoreClient {
sender: Sender<Command>,
}
impl TicketStoreClient {
// Feel free to panic on all errors, for simplicity.
pub fn insert(&self, draft: TicketDraft) -> TicketId {
// TODO
let (response_sender, response_receiver) = std::sync::mpsc::channel();//创建一个channel
//构造一个Command::Insert,因为是客户端,所以是把TicketDraft上传,并且设置供给接收方使用的sender
self.sender
.send(Command::Insert {
draft,
response_channel: response_sender,
})
.unwrap();
//客户端使用刚刚创建的channel对,对应接收server发回来的数据,返回值就是TicketId
response_receiver.recv().unwrap()
// TODO
}
pub fn get(&self, id: TicketId) -> Option<Ticket> {
// TODO
let (response_sender, response_receiver) = std::sync::mpsc::channel();
self.sender
.send(Command::Get {
id,
response_channel: response_sender,
})
.unwrap();
response_receiver.recv().unwrap()
// TODO
}
}
pub fn launch() -> TicketStoreClient {
let (sender, receiver) = std::sync::mpsc::channel();
std::thread::spawn(move || server(receiver));
// TODO
//这里的函数创建的才是真正供给client使用的channel对,receiver给了server,我们留下了sender
TicketStoreClient { sender }
// TODO
}
// No longer public! This becomes an internal detail of the library now.
enum Command {
Insert {
draft: TicketDraft,
response_channel: Sender<TicketId>,
},
Get {
id: TicketId,
response_channel: Sender<Option<Ticket>>,
},
}
fn server(receiver: Receiver<Command>) {
let mut store = TicketStore::new();
loop {
match receiver.recv() {
Ok(Command::Insert {
draft,
response_channel,
}) => {
let id = store.add_ticket(draft);
let _ = response_channel.send(id);
}
Ok(Command::Get {
id,
response_channel,
}) => {
let ticket = store.get(id);
let _ = response_channel.send(ticket.cloned());
}
Err(_) => {
// There are no more senders, so we can safely break
// and shut down the server.
break;
}
}
}
}
阅读剩余
版权声明:
作者:CN059
链接:https://www.cn059.com/2025/11/15/73%e3%80%81%e7%bb%83%e4%b9%a0%e5%ae%a2%e6%88%b7%e7%ab%af%e8%bf%9b%e9%98%b6.html
文章版权归作者所有,未经允许请勿转载。
THE END
