Rust + mio: got "move occurs value because" when store TcpStream inside struct field - struct

I want to implement TCP client using struct:
use std::error::Error;
use mio::net::{TcpListener, TcpStream};
use mio::{Events, Interest, Poll, Token};
use std::io::Read;
const CLIENT: Token = Token(0);
pub struct Client {
pub connected: bool,
connection: Option<TcpStream>,
}
impl Client {
pub fn connect(&mut self, host: &str, port: i16) {
let addr = format!("{}:{}", host, port).parse().unwrap();
if let Ok(stream) = TcpStream::connect(addr) {
self.connected = true;
self.connection = Some(stream);
} else {
println!("Cannot connect !");
}
}
pub fn listen(&mut self) {
let mut connection = self.connection.unwrap();
let mut poll = Poll::new().unwrap();
let mut events = Events::with_capacity(256);
poll.registry().register(
&mut connection,
CLIENT,
Interest::READABLE | Interest::WRITABLE
);
loop {
// ...
}
}
pub fn new() -> Client {
Client {
connected: false,
connection: None,
}
}
}
But I got an error:
let mut connection = self.connection.unwrap();
^^^^^^^^^^^^^^^ move occurs because `self.connection` has type `Option<mio::net::TcpStream>`, which does not implement the `Copy` trait
How can I fix this ?

Related

Rust send serialized struct from crossbeam channel to multiple receivers via tcp

I am trying to send a serialized struct over tcp to multiple machines. The tcp handler receives the serialized struct (String type) by a crossbeam channel from another thread.
My problem is that the rx.try_iter() will drain the crossbeam channel, and if more than one client is connected the clients can't receive the same struct. I tried moving the rx.try_iter() out of the individual handle_client() function, but couldn't achieve a good result.
Thanks for your time and help!
This is what I have so far:
(Server side)
use std::net::{TcpListener, TcpStream};
use std::thread;
use std::io::{Read,Write,Error};
use serde::{Serialize, Deserialize};
use crossbeam_channel::unbounded;
#[derive(Serialize, Deserialize)]
pub struct Serialized {
pub buffer: Vec<u32>,
pub timestep: u128,
}
impl Serialized {
pub fn serialize(buffer: Vec<u32>, timestep: u128) -> String {
let x = Serialized {
buffer,
timestep
};
serde_json::to_string(&x).unwrap()
}
}
fn handle_client(mut stream: TcpStream, rx: crossbeam_channel::Receiver<String>)-> Result<(), Error> {
println!("incoming connection from: {}", stream.peer_addr()?);
loop {
//receive from channel
let serialized = match rx.try_iter().last(){
Some(x) => x,
None => continue,
};
//write to stream
stream.write(serialized.as_bytes())?;
}
}
pub fn start_server(rx: crossbeam_channel::Receiver<String>) {
let listener = TcpListener::bind("localhost:8888").expect("Could not bind");
for stream in listener.incoming() {
let rx = rx.clone();
match stream {
Err(e)=> {eprintln!("failed: {}", e)}
Ok(stream) => {
thread::spawn(move || {
handle_client(stream, rx).unwrap_or_else(|error| eprintln!("{:?}", error));
});
}
}
}
}
(Client side)
use std::net::TcpStream;
use serde::{Serialize, Deserialize};
use std::error::Error as er;
#[derive(Serialize, Deserialize, Debug)]
pub struct Serialized {
pub buffer: Vec<u32>,
pub timestep: u128,
}
fn read_user_from_stream(tcp_stream: &mut TcpStream) -> Result<Serialized, Box<dyn er>> {
let mut de = serde_json::Deserializer::from_reader(tcp_stream);
let u = Serialized::deserialize(&mut de)?;
Ok(u)
}
pub fn start_client() {
loop {
let mut stream = TcpStream::connect("localhost:8888").expect("could not connect");
let serialized = read_user_from_stream(&mut stream).unwrap();
println!("timestep: {}", serialized.timestep);
}
}
fn main() {
start_client();
}
You can't use crossbeam to broadcast items. crossbeam only provides a producer-consumer architecture; if you want to deliver an item to multiple receivers, you need to use a different mechanism.
It seems that the bus crate provides what you need.
After some discussion on the rust user board, I came to this solution (server side):
use std::sync::{Arc, Mutex};
use std::thread;
use std::net::{TcpListener, TcpStream};
use std::io::{Read,Write,Error};
use bus::{Bus, BusReader};
fn main() {
let mut x: u32 = 0;
let bus = Bus::<u32>::new(10);
let bus_mutex = Arc::new(Mutex::new(bus));
let bus_mutex_cp = Arc::clone(&bus_mutex);
thread::spawn(move || {
start_server(bus_mutex_cp);
});
//simulation loop
for _ in 0..99999 {
x = x + 1;
println!("Simulation step: {}", x);
bus_mutex.lock().unwrap().broadcast(x);
thread::sleep_ms(1000);
}
loop {}
}
pub fn start_server(bus_mutex: Arc<Mutex<Bus<u32>>>) {
let listener = TcpListener::bind("0.0.0.0:8888").expect("Could not bind");
for stream in listener.incoming() {
match stream {
Err(e)=> {eprintln!("failed: {}", e)}
Ok(stream) => {
let rx = bus_mutex.lock().unwrap().add_rx();
thread::spawn(move || {
handle_client(stream, rx).unwrap_or_else(|error| eprintln!("{:?}", error));
});
}
}
}
}
fn handle_client(mut stream: TcpStream, mut rx: BusReader<u32>)-> Result<(), Error> {
println!("incoming connection from: {}", stream.peer_addr()?);
loop {
//receive from bus
let x = rx.recv().unwrap();
//write to stream
stream.write(&x.to_string().as_bytes())?;
thread::sleep_ms(100);
}
}

Not clear how to correctly define lifetime for struct

I have TCP Client, which process some handlers. I need to share data between them, so I implemented Session struct for this case:
struct Session<'a> {
pub session_key: Option<&'a Vec<u8>>,
pub username: Option<&'a str>,
pub password: Option<&'a str>,
}
impl Session {
pub fn new() -> Self {
Self {
session_key: None,
username: None,
password: None,
}
}
}
I added access by reference to allow data be borrowed.
But, when I try to use this struct inside my code, I got errors related to lifetime:
implicit elided lifetime not allowed here
or
cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
This is minimal sandbox implementation.
Just in case this is my sample code (mostly it's similar to my real app):
// data which store values that I need to share between handlers
struct Session<'a> {
pub session_key: Option<&'a Vec<u8>>,
pub username: Option<&'a str>,
pub password: Option<&'a str>,
}
// not sure if this correct to set &None below, where to put the lifetime here ?
impl Session {
pub fn new() -> Self {
Self {
session_key: None,
username: None,
password: None,
}
}
}
// what handler return
pub enum HandlerResponse {
Packet(Vec<u8>),
Void,
}
// handler params
pub struct HandlerInput<'a> {
session: &'a mut Session<'a>,
data: Option<Vec<u8>>
}
pub struct Client<'a> {
stream: Option<TcpStream>,
buffer: [u8; 4096],
session: Session<'a>,
}
// public methods
impl<'a> Client<'a> {
pub fn new() -> Self {
Self {
stream: None,
buffer: [0u8; 4096],
session: Session::new(),
}
}
pub fn connect(&mut self, host: &str, port: i16) {
let addr = format!("{}:{}", host, port);
match TcpStream::connect(&addr) {
Ok(stream) => {
self.stream = Some(stream);
println!("Connected to {}", addr);
},
_ => {
println!("Cannot connect");
},
}
}
pub fn handle_connection(
&mut self,
handlers: Vec<fn(HandlerInput
) -> Result<u8, Error>>) {
for handler in handlers {
self.process(handler);
}
}
}
// private methods
impl<'a> Client<'a> {
fn process<F>(&mut self, handler: F)
where
F: Fn(HandlerInput) -> Result<HandlerResponse, Error>
{
let response: Result<HandlerResponse, Error> = match self.handle_read() {
Ok(server_response) => handler(HandlerInput {
session: &mut self.session,
data: Some(server_response),
}),
_ => handler(HandlerInput {
session: &mut self.session,
data: None,
})
};
match response.unwrap() {
HandlerResponse::Packet(data) => {
self.handle_write(data).unwrap();
},
HandlerResponse::Void => {},
}
}
fn handle_write(&mut self, packet: Vec<u8>) -> Result<(), Error> {
let mut stream = self.stream.as_ref().unwrap();
match stream.write(&packet) {
Ok(_) => Ok(()),
_ => Err(Error::new(ErrorKind::Other, "Write error")),
}
}
fn handle_read(&mut self) -> Result<Vec<u8>, Error> {
let mut stream = self.stream.as_ref().unwrap();
let mut buffer = self.buffer.as_mut();
match stream.read(&mut buffer) {
Ok(bytes_count) => {
return Ok(buffer[ .. bytes_count].to_vec());
},
_ => Err(Error::new(ErrorKind::Other, "Read error")),
}
}
}
When I put lifetime on Client struct and then put lifetime on &'a mut self I got an error:
cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
Could you explain how to fix lifetimes here ?
UPDATED:
I need a reference inside Session because I want to use the values of the session inside handlers, if I not use reference, I got the error:
move occurs because input.session.session_key has type Option<Vec<u8>>, which does not implement the Copy trait
The code how I use the Session:
fn handler(input: HandlerInput) {
let hasher = Sha1::new();
let digest = hasher
.chain(input.session.username.unwrap())
.chain(input.session.session_key.unwrap())
.finalize();
}
Also sometimes I need to modify the input inside handler, something like:
let mut session = input.session;
session.session_key = Some(srp_client.session_key());
I can see two problems:
Your short sample code is missing lifetime annotations
Your longer code is an implementation that is almost impossible to achieve with borrows, and therefore I suspect that this question is an XY-problem.
Quick fix of your short code sample
Your impl is missing lifetimes:
pub struct Session<'a> {
pub session_key: Option<&'a Vec<u8>>,
pub username: Option<&'a str>,
pub password: Option<&'a str>,
}
impl<'a> Session<'a> {
pub fn new() -> Self {
Self {
session_key: None,
username: None,
password: None,
}
}
}
What you probably actually want
So my question is, why use borrows in the first place for Session?
You technically only need the reference in HandlerInput. Then, both handlers see the same Session object to modify.
use std::io::{Error, ErrorKind, Read, Write};
use std::net::TcpStream;
// data which store values that I need to share between handlers
struct Session {
pub session_key: Option<Vec<u8>>,
pub username: Option<String>,
pub password: Option<String>,
}
// not sure if this correct to set &None below, where to put the lifetime here ?
impl Session {
pub fn new() -> Self {
Self {
session_key: None,
username: None,
password: None,
}
}
}
// what handler return
pub enum HandlerResponse {
Packet(Vec<u8>),
Void,
}
// handler params
pub struct HandlerInput<'a> {
session: &'a mut Session,
data: Option<Vec<u8>>,
}
pub struct Client {
stream: Option<TcpStream>,
buffer: [u8; 4096],
session: Session,
}
// public methods
impl Client {
pub fn new() -> Self {
Self {
stream: None,
buffer: [0u8; 4096],
session: Session::new(),
}
}
pub fn connect(&mut self, host: &str, port: i16) {
let addr = format!("{}:{}", host, port);
match TcpStream::connect(&addr) {
Ok(stream) => {
self.stream = Some(stream);
println!("Connected to {}", addr);
}
_ => {
println!("Cannot connect");
}
}
}
pub fn handle_connection(
&mut self,
handlers: Vec<fn(HandlerInput) -> Result<HandlerResponse, Error>>,
) {
for handler in handlers {
self.process(handler);
}
}
}
// private methods
impl Client {
fn process<F>(&mut self, handler: F)
where
F: Fn(HandlerInput) -> Result<HandlerResponse, Error>,
{
let response: Result<HandlerResponse, Error> = match self.handle_read() {
Ok(server_response) => handler(HandlerInput {
session: &mut self.session,
data: Some(server_response),
}),
_ => handler(HandlerInput {
session: &mut self.session,
data: None,
}),
};
match response.unwrap() {
HandlerResponse::Packet(data) => {
self.handle_write(data).unwrap();
}
HandlerResponse::Void => {}
}
}
fn handle_write(&mut self, packet: Vec<u8>) -> Result<(), Error> {
let mut stream = self.stream.as_ref().unwrap();
match stream.write(&packet) {
Ok(_) => Ok(()),
_ => Err(Error::new(ErrorKind::Other, "Write error")),
}
}
fn handle_read(&mut self) -> Result<Vec<u8>, Error> {
let mut stream = self.stream.as_ref().unwrap();
let mut buffer = self.buffer.as_mut();
match stream.read(&mut buffer) {
Ok(bytes_count) => {
return Ok(buffer[..bytes_count].to_vec());
}
_ => Err(Error::new(ErrorKind::Other, "Read error")),
}
}
}
fn handler1(input: HandlerInput) -> Result<HandlerResponse, Error> {
Ok(HandlerResponse::Void)
}
fn handler2(input: HandlerInput) -> Result<HandlerResponse, Error> {
Ok(HandlerResponse::Void)
}
fn main() {
let mut client = Client::new();
client.connect("127.0.0.1", 8080);
client.handle_connection(vec![handler1, handler2]);
}
Compiles fine and should work.

Rust + mio tcp client: explicit lifetime required in the type of connection

I want to implement tcp client using mio. This is my code:
pub struct Client<'a> {
pub connected: bool,
connection: Option<&'a TcpStream>,
auth_handler: auth::AuthHandler<'a>,
}
impl Client<'_> {
pub fn connect(&mut self, host: &str, port: i16) {
let addr_list = format!("{}:{}", host, port)
.to_socket_addrs()
.unwrap();
let addr = addr_list.last().unwrap();
match TcpStream::connect(addr) {
Ok(stream) => {
self.connected = true;
self.connection = Some(&stream);
self.auth_handler.init(self.connection.unwrap());
self.auth_handler.authenticate("login".to_string(), "password".to_string());
println!("Connected to {}:{}", host, port);
}
Err(..) => {
println!("Cannot connect !");
}
}
}
pub fn listen(&mut self) {
let mut connection = self.connection.as_mut().unwrap();
let mut poll = Poll::new().unwrap();
let mut events = Events::with_capacity(256);
poll.registry().register(
connection,
CLIENT,
Interest::READABLE | Interest::WRITABLE
);
loop {
poll.poll(&mut events, None).unwrap();
for event in events.iter() {
match event.token() {
CLIENT => {
if event.is_writable() {
// ...
}
if event.is_readable() {
println!("Data")
}
},
_ => (),
}
}
}
}
pub fn new<'a>() -> Client<'a> {
Client {
connected: false,
connection: None,
auth_handler: auth::AuthHandler {
connection: None::<&'a TcpStream>,
},
}
}
}
and code of my auth handler:
pub struct AuthHandler<'a> {
pub connection: Option<&'a TcpStream>,
}
impl AuthHandler {
pub fn authenticate(&self, login: String, password: String) {
// ...
}
pub fn new<'a>() -> AuthHandler<'a> {
AuthHandler {
connection: None::<&'a TcpStream>,
}
}
pub fn init(&mut self, connection: &TcpStream) {
self.connection = Some(&connection); // error here see ERRORS below
}
}
on compile I got an error "error[E0621]: explicit lifetime required in the type of connection":
self.connection = Some(&connection);
^^^^^^^^^^^^^^^^^ lifetime `'static` required
how to fix it ? From my side I am not sure if static lifetime is OK since I want to destroy connection once authenticated and logged in.
The lifetime of connection is really 'a, but from the code you've posted nobody owns the TcpStream. You could fix the specific error you're having by using the AuthHandlers lifetime:
impl<'a> AuthHandler<'a> {
pub fn authenticate(&self, login: String, password: String) {
// ...
}
pub fn new() -> AuthHandler {
AuthHandler {
connection: None,
}
}
pub fn init(&mut self, connection: &'a TcpStream) {
self.connection = Some(connection);
}
}
But I would expect that you would then get other errors, because in effect Client is a self-referential struct.
So one way to share the connection between these objects would be to put it inside a Arc<Mutex<TcpStream>> and share that between your two objects:
pub struct Client<'a> {
pub connected: bool,
connection: Option<Arc<Mutex<TcpStream>>>,
auth_handler: auth::AuthHandler<'a>,
}
pub struct AuthHandler {
pub connection: Option<Arc<Mutex<TcpStream>>>,
}
then the TcpStream will stay alive as long as you need it. Of course, you would need to .lock() it whenever you use it.
Another option would be to only pass the TcpStream to AuthHandler when it uses it:
pub struct AuthHandler;
impl AuthHandler {
pub fn authenticate(&self, login: String, password: String, stream: &TcpStream) {
// ...
}
}

Cannot borrow data in an `Arc` as mutable

I don't know what to do next. It looks like I misunderstand something, or maybe I have not learned some critical topic.
use std::sync::Arc;
use reqwest::{Error, Response}; // 0.11.4
use tokio::sync::mpsc::{self, Receiver, Sender}; // 1.9.0
pub struct Task {
pub id: u32,
pub url: String,
}
pub enum Message {
Failure(Task, Error),
Success(Task, Response),
}
struct State {
client: reqwest::Client,
res_tx: Sender<Message>,
res_rx: Receiver<Message>,
}
pub struct Proxy {
state: Arc<State>,
max_rps: u16,
max_pending: u16,
id: u32,
parent_tx: Sender<String>,
}
async fn send_msg<T>(tx: &Sender<T>, msg: T) {
match tx.send(msg).await {
Err(error) => {
eprintln!("{}", error)
}
_ => (),
};
}
impl Proxy {
// Starts loop for input channel
async fn start_chin(&mut self) -> Sender<Task> {
let (chin_tx, mut chin_rx) = mpsc::channel::<Task>(self.max_pending as usize + 1 as usize);
let state_outer = self.state.clone();
tokio::spawn(async move {
loop {
match chin_rx.recv().await {
Some(task) => {
let res_tx = state_outer.res_tx.clone();
let state = state_outer.clone();
tokio::spawn(async move {
match state.client.get(&task.url).send().await {
Ok(res) => send_msg(&res_tx, Message::Success(task, res)).await,
Err(err) => send_msg(&res_tx, Message::Failure(task, err)).await,
}
});
}
None => (),
}
}
});
chin_tx
}
async fn start_chres(&self) {
let state = self.state.clone();
tokio::spawn(async move {
loop {
match state.res_rx.recv().await { // LINE PRODUCES ERROR
Some(task) => {}
None => (),
}
}
});
}
}
impl Proxy {
pub fn new(
id: u32,
parent_tx: Sender<String>,
proxy_addr: &str,
max_rps: u16,
max_pending: u16,
) -> Result<Self, Error> {
let client = reqwest::Client::builder();
if proxy_addr != "none" {
client = client.proxy(reqwest::Proxy::all(proxy_addr)?)
}
let (res_tx, res_rx) = mpsc::channel::<Message>(max_pending as usize + 1 as usize); // TODO: check size
Ok(Proxy {
id,
state: Arc::new(State {
client: client.build()?,
res_tx,
res_rx,
}),
max_rps,
max_pending,
parent_tx,
})
}
}
error[E0596]: cannot borrow data in an `Arc` as mutable
--> src/lib.rs:69:23
|
69 | match state.res_rx.recv().await {
| ^^^^^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<State>`
use std::sync::Arc;
struct Something {
size: usize
}
impl Something {
fn increase(&mut self) {
self.size = self.size + 1;
}
}
fn main() {
let something = Something{size: 1};
let arc = Arc::new(something);
arc.increase();
}
gives
error[E0596]: cannot borrow data in an `Arc` as mutable
--> src/main.rs:16:5
|
16 | arc.increase();
| ^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<Something>`
error: aborting due to previous error; 1 warning emitted
because it tries to borrow arc as mutable. For it to happen, DerefMut would have to be implemented for Arc but it's not because Arc is not meant to be mutable.
Wraping your object in a Mutex works:
use std::sync::{Arc, Mutex};
struct Something {
size: usize
}
impl Something {
fn increase(&mut self) {
self.size = self.size + 1;
}
}
fn main() {
let something = Something{size: 1};
let arc = Arc::new(Mutex::new(something));
arc.lock().unwrap().increase();
}
Now it can be shared and can be increased.
Lucas Zanella's answer and Shepmaster's comments helped alot to refactor and simplify code. I've desided to pass ownership inside Proxy::new() function instead of using shared reference. The code became more readable, and I've avoided shared reference for mutable tokio::sync::mpsc::Receiver. Perhaps the question turned out to be too unstructured, but I came to a new approach thanks to the community. Refactored code is listed below.
use reqwest::{Client, Error, Response};
use tokio::sync::mpsc;
use tokio::sync::mpsc::{Sender, Receiver};
pub struct Task {
pub id: u32,
pub url: String,
}
pub enum Message{
Failure(Task, Error),
Success(Task, Response),
}
pub struct Proxy{
id: u32,
max_rps: u16,
max_pending: u16,
in_tx: Sender<Task>,
}
async fn send_msg<T>(tx: &Sender<T>, msg: T){
match tx.send(msg).await {
Err(error) => { eprintln!("{}", error) },
_ => (),
};
}
async fn start_loop_in(client: Client, mut in_rx: Receiver<Task>, res_tx: Sender<Message>){
loop {
if let Some(task) = in_rx.recv().await {
let client_clone = client.clone();
let res_tx_clone = res_tx.clone();
tokio::spawn(async move {
println!("SENDING: {}", &task.url); // TODO: DELETE DEBUG
match client_clone.get(&task.url).send().await {
Ok(res) => send_msg(&res_tx_clone, Message::Success(task, res)).await,
Err(err) => send_msg(&res_tx_clone, Message::Failure(task, err)).await,
}
});
}
}
}
async fn start_loop_res(mut res_rx: Receiver<Message>, out_tx: Sender<String>){
loop {
if let Some(message) = res_rx.recv().await {
match message {
Message::Success(task, res) => {
send_msg(
&out_tx,
format!("{:#?}", res.text().await.unwrap()) // TODO: change in release!
).await;
},
Message::Failure(task, err) => {
send_msg(&out_tx, err.to_string()).await;
},
}
}
}
}
impl Proxy{
pub fn new(id: u32, parent_tx: Sender<String>, proxy_addr: &str, max_rps: u16, max_pending: u16) -> Result<Self, Error> {
let mut client = Client::builder();
if proxy_addr != "none" { client = client.proxy(reqwest::Proxy::all(proxy_addr)?) }
let (res_tx, res_rx) = mpsc::channel::<Message>(max_pending as usize + 1 as usize); // TODO: check size
let client = client.build()?;
let (in_tx, in_rx) = mpsc::channel::<Task>(max_pending as usize + 1 as usize);
let res_tx_clone = res_tx.clone();
tokio::spawn(async move { start_loop_in(client, in_rx, res_tx_clone).await });
tokio::spawn(async move { start_loop_res(res_rx, parent_tx).await });
Ok(Proxy{
id,
max_rps,
max_pending,
in_tx,
})
}
pub fn get_in_tx(&self) -> Sender<Task> {
self.in_tx.clone()
}
}

Using trait methods in threads

Basically, I'm making a program that's listening to a bunch of ports and that handles incoming packets in different ways. I decide to bundle this code into a Trait:
use std::old_io::{TcpStream, TcpListener, Listener, Acceptor, EndOfFile, IoResult};
use std::thread::Thread;
trait Server {
fn new(port: u16) -> Self;
fn hostname(&self) -> &String;
fn initialize(&self) {
let acceptor = TcpListener::bind(self.hostname().as_slice()).listen().unwrap();
Thread::spawn(move|| {
let mut acceptor = acceptor;
for incoming_stream in acceptor.incoming() {
match incoming_stream {
Ok(stream) => {
self.handle_client(stream);
},
Err(ref e) if e.kind == EndOfFile => break,
Err(e) => panic!("Unexpected error: {}", e),
}
}
});
}
fn handle_client(&self, stream: TcpStream) -> ();
}
pub struct InternodeServer {
hostname: String,
}
impl Server for InternodeServer {
fn new(port: u16) -> InternodeServer {
let hostname = format!("127.0.0.1:{}", port);
InternodeServer {
hostname: hostname,
}
}
fn hostname(&self) -> &String {
&self.hostname
}
fn handle_client(&self, stream: TcpStream) {
println!("Received connection");
let mut stream = stream;
let response = b"Hello\r\n";
let _ = stream.write_all(response);
let _ = stream.close_write();
}
}
fn main() {
let test_server = <InternodeServer as Server>::new(9337);
test_server.initialize();
}
However, this code won't work because you can't send Self. This is the error I receive:
test.rs:11:9: 11:22 error: the trait `core::marker::Send` is not implemented for the type `Self` [E0277]
test.rs:11 Thread::spawn(move|| {
^~~~~~~~~~~~~
test.rs:11:9: 11:22 note: `Self` cannot be sent between threads safely
test.rs:11 Thread::spawn(move|| {
^~~~~~~~~~~~~
So I also tried making handle_client a static method to avoid self. To do this, I simply changed handle_client to:
fn handle_client(stream: TcpStream)
And referenced it by doing:
Server::handle_client(stream);
However, I can't reference InternodeServer's static methods from Server's initialize method. When compiling, I get an error like:
test.rs:16:25: 16:46 error: type annotations required: cannot resolve `_ : Server` [E0283]
test.rs:16 Server::handle_client(stream);
^~~~~~~~~~~~~~~~~~~~~
test.rs:16:25: 16:46 note: required by `Server::handle_client`
test.rs:16 Server::handle_client(stream);
Is there any way around this?
Here's a smaller reproduction of the error:
use std::thread::Thread;
trait Server {
fn initialize(&self) {
Thread::spawn(move || self.handle_client());
}
fn handle_client(&self);
}
fn main() {}
The problem is that the argument passed to Thread::spawn must be Send. You are trying to move self into the closure, but your trait doesn't guarantee Send, so the closure can't be Send.
We can attempt to go down that path with trait Server: Send, but then we get "cannot infer an appropriate lifetime" errors because Send also requires 'static (for now). Also, it seems very strange to move yourself into a closure.
Really, I think you want to split up your code. Move handle_client into a separate trait and then ensure that implementations of that trait are Send:
use std::thread::Thread;
trait Server {
fn initialize<D>(&self, driver: D)
where D: Driver + Send
{
Thread::spawn(move || driver.handle_client());
}
}
trait Driver {
fn handle_client(&self);
}
fn main() {}
I don't think that rust will allow you to invoke object methods directly from other thread because "move" closures cannot borrow anything, only move.
So you have to use some kind of inter-thread communication tool, for example, channels:
use std::thread::Thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender, Receiver, RecvError};
use std::net::{TcpStream, TcpListener};
use std::io::{ErrorKind, Write};
trait Server {
fn new(port: u16) -> Self;
fn hostname(&self) -> &String;
fn initialize(&mut self, _detached: bool) {
let acceptor = TcpListener::bind(self.hostname().as_slice()).unwrap();
let server_tx = self.make_pipe();
Thread::spawn(move|| {
for incoming_stream in acceptor.incoming() {
match incoming_stream {
Ok(stream) => server_tx.send(Arc::new(Mutex::new(stream))).unwrap(),
Err(ref e) if e.kind() == ErrorKind::NotConnected => break,
Err(e) => panic!("Unexpected error: {}", e),
}
}
});
}
fn handle_client(&self, stream: Arc<Mutex<TcpStream>>);
fn make_pipe(&mut self) -> Sender<Arc<Mutex<TcpStream>>>;
fn run(&self);
}
pub struct InternodeServer {
hostname: String,
client_rx: Option<Receiver<Arc<Mutex<TcpStream>>>>,
}
impl Server for InternodeServer {
fn new(port: u16) -> InternodeServer {
let hostname = format!("127.0.0.1:{}", port);
InternodeServer {
hostname: hostname,
client_rx: None,
}
}
fn make_pipe(&mut self) -> Sender<Arc<Mutex<TcpStream>>> {
let (server_tx, client_rx) = channel();
self.client_rx = Some(client_rx);
server_tx
}
fn hostname(&self) -> &String {
&self.hostname
}
fn handle_client(&self, stream_arc: Arc<Mutex<TcpStream>>) {
println!("Received connection");
let mut stream = stream_arc.lock().unwrap();
let response = b"Hello\r\n";
let _ = stream.write_all(response);
let _ = drop(stream);
}
fn run(&self) {
loop {
match self.client_rx.as_ref().unwrap().recv() {
Ok(stream) => self.handle_client(stream),
Err(RecvError) => break,
}
}
}
}
fn main() {
let mut s = <InternodeServer as Server>::new(10101);
s.initialize(false);
s.run();
}

Resources