|
@@ -7,19 +7,14 @@ extern crate serde_derive;
|
|
|
extern crate serde_json;
|
|
|
extern crate tokio_core;
|
|
|
|
|
|
-use std::io;
|
|
|
-use std::net::SocketAddr;
|
|
|
-use std::thread;
|
|
|
|
|
|
-use futures::{Future, Stream};
|
|
|
+use futures::Future;
|
|
|
|
|
|
use hyper::{Body, Response, StatusCode};
|
|
|
use hyper::header::{CONTENT_LENGTH, CONTENT_TYPE, SERVER, HeaderValue};
|
|
|
-use hyper::server::conn::Http;
|
|
|
use hyper::service::service_fn_ok;
|
|
|
|
|
|
-use tokio_core::reactor::{Core, Handle};
|
|
|
-use tokio_core::net::TcpListener;
|
|
|
+mod server;
|
|
|
|
|
|
static HELLO_WORLD: &'static [u8] = b"Hello, world!";
|
|
|
|
|
@@ -28,11 +23,8 @@ struct JsonResponse<'a> {
|
|
|
message: &'a str,
|
|
|
}
|
|
|
|
|
|
-fn server_thread() {
|
|
|
- // Configure HTTP options
|
|
|
- let mut http = Http::new();
|
|
|
- http.pipeline_flush(true);
|
|
|
|
|
|
+fn main() {
|
|
|
// It seems most of the other benchmarks create static header values
|
|
|
// for performance, so just play by the same rules here...
|
|
|
let plaintext_len = HeaderValue::from_static("13");
|
|
@@ -41,8 +33,12 @@ fn server_thread() {
|
|
|
let json_ct = HeaderValue::from_static("application/json");
|
|
|
let server_header = HeaderValue::from_static("hyper");
|
|
|
|
|
|
- // This will create our `Service` to handle an individual connection.
|
|
|
- let new_svc = move || {
|
|
|
+ server::run(move |socket, http, handle| {
|
|
|
+ // This closure is run for each connection...
|
|
|
+
|
|
|
+ // The plaintext benchmarks use pipelined requests.
|
|
|
+ http.pipeline_flush(true);
|
|
|
+
|
|
|
// Gotta clone these to be able to move into the Service...
|
|
|
let plaintext_len = plaintext_len.clone();
|
|
|
let plaintext_ct = plaintext_ct.clone();
|
|
@@ -53,7 +49,7 @@ fn server_thread() {
|
|
|
// This is the `Service` that will handle the connection.
|
|
|
// `service_fn_ok` is a helper to convert a function that
|
|
|
// returns a Response into a `Service`.
|
|
|
- service_fn_ok(move |req| {
|
|
|
+ let svc = service_fn_ok(move |req| {
|
|
|
let (req, _body) = req.into_parts();
|
|
|
// For speed, reuse the allocated header map from the request,
|
|
|
// instead of allocating a new one. Because.
|
|
@@ -88,61 +84,13 @@ fn server_thread() {
|
|
|
let mut res = Response::new(body);
|
|
|
*res.headers_mut() = headers;
|
|
|
res
|
|
|
- })
|
|
|
- };
|
|
|
-
|
|
|
- // Our event loop...
|
|
|
- let mut core = Core::new().expect("core");
|
|
|
- let handle = core.handle();
|
|
|
-
|
|
|
- // Bind to 0.0.0.0:8080
|
|
|
- let addr = SocketAddr::from(([0, 0, 0, 0], 8080));
|
|
|
- let tcp = reuse_listener(&addr, &handle)
|
|
|
- .expect("couldn't bind to addr");
|
|
|
-
|
|
|
- // For every accepted connection, spawn an HTTP task
|
|
|
- let server = tcp.incoming()
|
|
|
- .for_each(move |(sock, _addr)| {
|
|
|
- let _ = sock.set_nodelay(true);
|
|
|
- let conn = http.serve_connection(sock, new_svc())
|
|
|
- .map_err(|e| eprintln!("connection error: {}", e));
|
|
|
-
|
|
|
- handle.spawn(conn);
|
|
|
-
|
|
|
- Ok(())
|
|
|
- })
|
|
|
- .map_err(|e| eprintln!("accept error: {}", e));
|
|
|
-
|
|
|
- core.run(server).expect("server");
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-fn reuse_listener(addr: &SocketAddr, handle: &Handle) -> io::Result<TcpListener> {
|
|
|
- let builder = match *addr {
|
|
|
- SocketAddr::V4(_) => net2::TcpBuilder::new_v4()?,
|
|
|
- SocketAddr::V6(_) => net2::TcpBuilder::new_v6()?,
|
|
|
- };
|
|
|
-
|
|
|
- #[cfg(unix)]
|
|
|
- {
|
|
|
- use net2::unix::UnixTcpBuilderExt;
|
|
|
- if let Err(e) = builder.reuse_port(true) {
|
|
|
- eprintln!("error setting SO_REUSEPORT: {}", e);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- builder.reuse_address(true)?;
|
|
|
- builder.bind(addr)?;
|
|
|
- builder.listen(1024).and_then(|l| {
|
|
|
- TcpListener::from_listener(l, addr, handle)
|
|
|
+ });
|
|
|
+
|
|
|
+ // Spawn the `serve_connection` future into the runtime.
|
|
|
+ handle.spawn(
|
|
|
+ http
|
|
|
+ .serve_connection(socket, svc)
|
|
|
+ .map_err(|e| eprintln!("connection error: {}", e))
|
|
|
+ );
|
|
|
})
|
|
|
}
|
|
|
-
|
|
|
-fn main() {
|
|
|
- // Spawn a thread for each available core, minus one, since we'll
|
|
|
- // reuse the main thread as a server thread as well.
|
|
|
- for _ in 1..num_cpus::get() {
|
|
|
- thread::spawn(server_thread);
|
|
|
- }
|
|
|
- server_thread();
|
|
|
-}
|