Tokio服务器直到被杀死才发送

时间:2017-02-02 22:49:02

标签: tcp rust future

我正在使用Tokio编写客户端和服务器,密切关注tokio网站上的echo serverhttp 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字节;没有效果。我不知道如何在响应流上触发手动刷新,但我不相信我应该这样做。

Runnable,最小示例

服务器/ SRC / main.rs

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));
}

的客户机/ SRC / main.rs

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;键入的字符串将在终止时回显到客户端窗口

0 个答案:

没有答案
相关问题