我正在使用Tokio编写客户端和服务器,密切关注tokio网站上的echo server和http client教程。我的项目是here。
实际问题是服务器生成的响应在服务器被杀之前不会发送到客户端。
Codec
编码方法fn encode(&mut self, msg: Self::Out, buf: &mut Vec<u8>) -> io::Result<()> {
println!("server encoding");
match msg.response_type {
CommandResult::SUCCESS => println!("server says success"),
CommandResult::FAILURE => println!("server says failure")
}
buf.extend(msg.response_type.as_bytes());
buf.push(b'\n');
let mut length = vec![0; 8];
BigEndian::write_u64(&mut length, msg.length);
buf.extend(length.as_slice());
buf.push(b'\n');
buf.extend(msg.data);
Ok(())
}
我在println!
下方添加了buf.extend(msg.data);
,并在手动终止服务器之前验证了它已执行。
fn main() {
let addr = "0.0.0.0:8080".parse().unwrap();
let server = TcpServer::new(CacheCommandProto, addr);
let cache = Arc::new(Mutex::new(LruCache::new(u64::pow(2, 9))));
server.serve(move || Ok(
CacheSrv {
cache: cache.clone()
}));
}
fn send_request(&self, cmd: CacheCommand) -> io::Result<CacheResponse> {
let mut core = Core::new().unwrap();
let handle = core.handle();
let socket = TcpStream::connect(&self.address, &handle);
println!("socket connected");
let mut codec = CacheClientCodec {};
let mut payload = vec![];
let _ = codec.encode(cmd, &mut payload);
println!("encoded");
core.run(
socket.and_then(|_socket| {
println!("write all");
tokio_core::io::write_all(_socket, payload)
}).and_then(|(_socket, _)| {
println!("read to end");
tokio_core::io::read_to_end(_socket, vec![])
}).map(move |(_, data)| {
println!("decode");
codec.decode(&mut EasyBuf::from(data))
}).and_then(|result| {
println!("coalesce");
result.and_then(|option| option.ok_or(io::Error::new(io::ErrorKind::Other, "no result")))
})
)
}
我正在使用pipeline::ServerProto
crate:{/ p>中的tokio_proto
impl<T: Io + 'static> ServerProto<T> for CacheCommandProto {
type Request = CacheCommand;
type Response = CacheResponse;
type Transport = Framed<T, CacheServerCodec>;
type BindTransport = Result<Self::Transport, io::Error>;
fn bind_transport(&self, io: T) -> Self::BindTransport {
Ok(io.framed(CacheServerCodec {}))
}
}
所有这些的结构与教程中的相同;服务器发送回声不需要显式刷新。
我尝试在编码方法中在缓冲区的末尾添加一个额外的\n
字节;没有效果。我不知道如何在响应流上触发手动刷新,但我不相信我应该这样做。
extern crate futures;
extern crate tokio_core;
extern crate tokio_proto;
extern crate tokio_service;
use std::io;
use std::str;
use tokio_core::io::{ Codec, EasyBuf, Io, Framed };
use tokio_proto::TcpServer;
use tokio_proto::pipeline::ServerProto;
use tokio_service::Service;
use futures::{ future, Future, BoxFuture };
pub struct LineCodec;
impl Codec for LineCodec {
type In = String;
type Out = String;
fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Self::In>> {
if let Some(i) = buf.as_slice().iter().position(|&b| b == b'\n') {
let line = buf.drain_to(i);
buf.drain_to(1);
match str::from_utf8(line.as_slice()) {
Ok(s) => Ok(Some(s.to_string())),
Err(_) => Err(io::Error::new(io::ErrorKind::Other, "invalid UTF-8"))
}
} else {
Ok(None)
}
}
fn encode(&mut self, msg: String, buf: &mut Vec<u8>) -> io::Result<()> {
buf.extend(msg.as_bytes());
buf.push(b'\n');
Ok(())
}
}
pub struct LineProto;
impl<T: Io + 'static> ServerProto<T> for LineProto {
type Request = String;
type Response = String;
type Transport = Framed<T, LineCodec>;
type BindTransport = Result<Self::Transport, io::Error>;
fn bind_transport(&self, io: T) -> Self::BindTransport {
Ok(io.framed(LineCodec))
}
}
pub struct Echo;
impl Service for Echo {
type Request = String;
type Response = String;
type Error = io::Error;
type Future = BoxFuture<Self::Response, Self::Error>;
fn call(&self, req: Self::Request) -> Self::Future {
future::ok(req).boxed()
}
}
fn main() {
let addr = "0.0.0.0:12345".parse().unwrap();
let server = TcpServer::new(LineProto, addr);
server.serve(|| Ok(Echo));
}
extern crate futures;
extern crate tokio_core;
use std::io;
use std::str;
use std::io::{ BufReader, BufRead };
use std::net::ToSocketAddrs;
use tokio_core::io::{ Codec, EasyBuf };
use tokio_core::net::TcpStream;
use tokio_core::reactor::Core;
use futures::Future;
pub struct LineCodec;
impl Codec for LineCodec {
type In = String;
type Out = String;
fn decode(&mut self, buf: &mut EasyBuf) -> io::Result<Option<Self::In>> {
if let Some(i) = buf.as_slice().iter().position(|&b| b == b'\n') {
let line = buf.drain_to(i);
buf.drain_to(1);
match str::from_utf8(line.as_slice()) {
Ok(s) => Ok(Some(s.to_string())),
Err(_) => Err(io::Error::new(io::ErrorKind::Other, "invalid UTF-8"))
}
} else {
Ok(None)
}
}
fn encode(&mut self, msg: String, buf: &mut Vec<u8>) -> io::Result<()> {
buf.extend(msg.as_bytes());
buf.push(b'\n');
Ok(())
}
}
fn main() {
let mut core = Core::new().unwrap();
let handle = core.handle();
let addr = "0.0.0.0:12345".to_socket_addrs().unwrap().next().unwrap();
let stdin = io::stdin();
let reader = BufReader::new(stdin);
for res in reader.lines() {
match res {
Ok(line) => {
let socket = TcpStream::connect(&addr, &handle);
let mut codec = LineCodec {};
let mut payload = vec![];
let _ = codec.encode(line, &mut payload);
println!("encoded");
let result = core.run(
socket.and_then(|_socket| {
println!("write all");
tokio_core::io::write_all(_socket, payload)
}).and_then(|(_socket, _)| {
println!("read to end");
tokio_core::io::read_to_end(_socket, vec![])
}).map(move |(_, data)| {
println!("decode");
codec.decode(&mut EasyBuf::from(data))
}).and_then(|result| {
println!("coalesce");
result.and_then(|option| option.ok_or(io::Error::new(io::ErrorKind::Other, "no result")))
})
);
match result {
Ok(returned) => println!("{}", returned),
Err(e) => println!("Error: {}", e)
}
}
Err(e) => println!("error: {}", e)
}
}
}
futures = "0.1"
tokio-core = "0.1"
tokio-service = "0.1"
tokio-proto = "0.1"
这只是将输入回送给客户端。但是,在服务器终止之前,客户端不会收到响应。
运行:
在一个终端中,cargo run
服务器
在第二个终端中,cargo run
客户端
在客户端窗口中,键入内容,然后按Enter键。它不会被回应。
在服务器窗口中,ctrl-c;键入的字符串将在终止时回显到客户端窗口