3.4 发送消息
现在是时候实现另一半了——发送消息。
实现发送的一个最明显的方法是让每个connection_loop访问彼此客户端的TcpStream的写半部分。
这样,客户端就可以直接向所有接收人发送消息。
但是,这是错误的:如果Alice给bob发送foo,Charley给bob发送bar,bob实际上可能会收到fobaor。
通过套接字发送消息可能需要几个系统调用,因此两个并发的。所有的写操作可能相互干扰!
根据经验,只有一个任务应该写入每个TcpStream。因此,让我们创建一个connection_writer_loop任务,
它通过一个通道接收消息并将它们写入套接字。此任务将是消息序列化的重点。
如果Alice和Charley同时向Bob发送两条消息,Bob将在消息到达频道时以相同的顺序看到这些消息。
use futures::channel::mpsc; // 1
use futures::sink::SinkExt;
use std::sync::Arc;
type Sender<T> = mpsc::UnboundedSender<T>; // 2
type Receiver<T> = mpsc::UnboundedReceiver<T>;
async fn connection_writer_loop(
mut messages: Receiver<String>,
stream: Arc<TcpStream>, // 3
) -> Result<()> {
let mut stream = &*stream;
while let Some(msg) = messages.next().await {
stream.write_all(msg.as_bytes()).await?;
}
Ok(())
}
- 我们将使用futures库的channels。
- 为了简单起见,我们将使用无限通道,而不会在本教程中讨论背压。
- 由于connection_loop和connection_writer_loop共享同一个TcpStream,我们需要将其放入一个Arc中。注意,因为客户端只从流中读取,而connection_writer_loop只写入流,所以我们在这里不存在竞争。