Lifetimes in for loop - rust

How can I specify lifetimes in a for loop? I'm trying to multithread ports, but keep running into lifetime issues.
pub fn connect_server(&self) {
for x in 58350..58360 {
thread::spawn(|| {
match TcpListener::bind(self.local_ip.to_string() + &x.to_string()) {
Ok(socket) => {
for stream in socket.accept() {
println!("received packet: {:?}", stream);
}
},
Err(error) => panic!("Failed to connect socket: {}", error)
}
});
thread::sleep(Duration::from_millis(1));
}
}
error:
borrowed data escapes outside of associated function
`self` escapes the associated function body here

Generate the bind address outside the thread::spawn closure, and use a move closure rather than capturing by reference:
pub fn connect_server(&self) {
for x in 58350..58360 {
let bind_address = format!("{}{}", self.local_ip, x);
thread::spawn(move || {
match TcpListener::bind(bind_address) {
Ok(socket) => {
for stream in socket.accept() {
println!("received packet: {:?}", stream);
}
},
Err(error) => panic!("Failed to connect socket: {}", error)
}
});
thread::sleep(Duration::from_millis(1));
}
}

Related

rust tokio recv broadcast only once

I can't receive message only one.
When I use 2 Thread first is only send value, second thread only recv value.
What is problem?
let (tx, mut rx) = broadcast::channel(1); // bradcast
let handle = tokio::spawn(async move {
let mut valu = 10;
loop{
valu += 10;
tx.send(valu).unwrap();
thread::sleep(Duration::from_secs(1));
if(valu >= 100){
break;
}
}
});
let handle1 = tokio::spawn(async move{
loop {
// first message recv and stuck
let _result = rx.recv().await;
match _result {
Ok(value)=>{
println!("=====> : {}", value);
},
Err(e)=>{
println!("err : {}", e );
break;
}
}
}
});
`
Never, ever, use std::thread::sleep() in async code. It blocks.
If you use tokio::time::sleep(), it works:
let (tx, mut rx) = broadcast::channel(1); // bradcast
let handle = tokio::spawn(async move {
let mut valu = 10;
loop {
valu += 10;
tx.send(valu).unwrap();
tokio::time::sleep(Duration::from_seconds(1)).await;
if valu >= 100 {
break;
}
}
});
let handle1 = tokio::spawn(async move {
loop {
let _result = rx.recv().await;
match _result {
Ok(value) => {
println!("=====> : {}", value);
}
Err(e) => {
println!("err : {}", e);
break;
}
}
}
});

Combining multi-pattern with conditionals in match

I'm trying to check if a variable b of a type Option<A> is equal to a of the same type A or None. It would seem idiomatic to use a match statement with multi pattern Some(a) | None, but I can't find a way to make it work.
Is there a way to express this pattern using match or should I just use a normal if pattern?
Example (also in https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=217b4559a73d59409f1d6afe7365d57c):
fn main() {
let a = 3;
let b = Some(5);
// Works but has code duplication
match b {
Some(b_val) if b_val == a => {
println!("do something");
}
None => {
println!("do something");
}
Some(_) => {
println!("do something else");
}
}
// Works but not very idiomatic
if b.is_none() || b.unwrap() == a {
println!("do something");
} else {
println!("do something else");
}
// Does not work
match b {
Some(b_val) if b_val == a | None => {
println!("do something");
}
Some(_) => {
println!("do something else");
}
}
}
I can only come up with a const a:
fn main() {
const a: i32 = 3;
let b = Some(5);
match b {
Some(a) | None => {
println!("do something");
}
_ => {
println!("do something else");
}
}
}
Or use if:
fn main() {
let a = 3;
let b = Some(5);
if b == None || b == Some(a) {
println!("do something");
} else {
println!("do something else");
}
}
Output:
do something else
You can check inequality instead of equality:
match b {
Some(b_val) if b_val != a => {
println!("do something else");
}
_ => {
println!("do something");
}
}

Buffering serial ouput and parsing JSON

I'm new to rust and struggling with an issue. I'm looking to read output from serial and convert it to JSON.
Below is the section of code that reads in the serial output.
match serialport::open(&port_name) {
Ok(mut port) => {
let mut serial_buf: Vec<u8> = vec![0; 1000];
loop {
match port.read(serial_buf.as_mut_slice()) {
Ok(t) => handle_event(&serial_buf[..t]),
Err(ref e) if e.kind() == io::ErrorKind::TimedOut => (),
Err(e) => print!("Port read error: {}\n", e),
};
}
}
Err(e) => {
println!("Failed to open \"{}\". Error: {}", port_name, e);
::std::process::exit(1);
}
};
Next that output is passed to serde to be parsed. However the output it gets isn't always the complete JSON string so serde breaks. I believe I need to buffer the response here but struggling to fit that in.
fn handle_event(buf: &[u8]) {
let e_str = match str::from_utf8(buf) {
Ok(v) => v,
Err(e) => { print!("Str conversion error: {}\n", e); return; },
};
let e = match serde_json::from_str::<Event>(e_str) {
Ok(e) => e,
Err(e) => { print!("JSON parse error: {}\n", e); return; },
};
print!("{}", e.name);
}
Thanks in advance for any help.

Why does an edge-triggered epoll loop freeze at the end of a HTTP load test?

I'm writing a HTTP server and I want to have one thread per CPU and each thread controls a separate epoll instance. I've implemented a test version of edge-triggered epoll using the nix crate, but I don't understand whats wrong with it.
When I'm testing this with ab (ab -n 200000 -c 1000) it works fast,
but at the end of testing epoll freezes. I don't know whats wrong, maybe I've broken the epoll state or I need to use the inner states of the client?
extern crate nix;
use nix::errno::Errno;
use nix::fcntl::*;
use nix::sys::epoll::EpollCreateFlags;
use nix::sys::epoll::*;
use nix::sys::socket::sockopt::ReuseAddr;
use nix::sys::socket::*;
use nix::unistd::close;
use nix::unistd::{read, write};
use nix::Error;
use std::collections::HashMap;
use std::os::unix::io::RawFd;
use std::thread;
const BUFSIZE: usize = 16384;
#[derive(Hash, Eq, PartialEq, Debug, Clone, Copy)]
pub enum State {
Read,
Write,
}
#[derive(Clone, Debug)]
pub struct Client {
pub readed: Vec<u8>,
pub state: State,
}
impl Client {
fn new() -> Self {
Client {
readed: Vec::new(),
state: State::Read,
}
}
}
fn socket_to_nonblock(sock: RawFd) -> Result<(), nix::Error> {
let flags = match fcntl(sock, F_GETFL) {
Ok(fl) => fl,
Err(err) => return Err(err),
};
let new_flags = flags | OFlag::O_NONBLOCK.bits();
let new_flags = OFlag::from_bits(new_flags).unwrap();
match fcntl(sock, F_SETFL(new_flags)) {
Ok(_) => return Ok(()),
Err(err) => return Err(err),
}
}
fn epoll_loop(server_sock: RawFd) -> nix::Result<()> {
let mut clients: HashMap<RawFd, Client> = HashMap::new(); //SockFlag::EPOLLET
let epfd = epoll_create1(EpollCreateFlags::from_bits(0).unwrap())?;
let mut ev = EpollEvent::new(
EpollFlags::EPOLLIN | EpollFlags::EPOLLOUT,
server_sock as u64,
);
epoll_ctl(epfd, EpollOp::EpollCtlAdd, server_sock, &mut ev)?;
let mut epoll_events = vec![EpollEvent::empty(); 1024];
let buffer = [0; BUFSIZE];
let critical_error = false;
let mut accepted = 0;
let mut closed = 0;
let mut refused = 0;
loop {
let nfds = match epoll_wait(epfd, &mut epoll_events, -1) {
Ok(n) => n,
Err(e) => {
println!("Err wait {:?}", e);
panic!();
}
};
for i in 0..nfds {
let cur_socket = epoll_events[i].data() as i32;
let cur_event = epoll_events[i].events();
if cur_event == cur_event & EpollFlags::EPOLLERR
|| cur_event == cur_event & EpollFlags::EPOLLHUP
|| cur_event != cur_event & (EpollFlags::EPOLLIN | EpollFlags::EPOLLOUT)
{
println!("error big if {:?}", cur_event);
close(epoll_events[i].data() as i32);
continue;
}
if server_sock == cur_socket {
loop {
let client_fd = match accept(server_sock) {
Ok(client) => {
accepted += 1;
if (client < 0) {
println!("JOPA");
panic!();
}
println!(
"Accepted {:?} Closed {:?} Dif: {:?} Refused {:?} Events len: {:?}",
accepted,
closed,
accepted - closed,
refused,
nfds
);
client
}
Err(err) => {
refused += 1;
println!("Error accept {:?}", err);
break;
}
};
match socket_to_nonblock(client_fd) {
Ok(_) => {}
Err(err) => println!("Non block err {:?}", err),
}
let mut ev = EpollEvent::new(
EpollFlags::EPOLLIN | EpollFlags::EPOLLET,
client_fd as u64,
);
match epoll_ctl(epfd, EpollOp::EpollCtlAdd, client_fd, &mut ev) {
Ok(e) => {}
Err(err) => println!("Server accept ctl {:?}", err),
}
println!("{:?}", clients.insert(client_fd, Client::new()));
break;
}
println!("loop breaked");
continue;
}
if cur_event == cur_event & EpollFlags::EPOLLIN {
let mut buf: [u8; 2048] = [0; 2048];
let client = clients.get_mut(&cur_socket).unwrap();
loop {
let mut total_len = client.readed.len();
let size = match read(cur_socket, &mut buf[total_len..]) {
Ok(size) => {
client.readed.extend_from_slice(&buf[..size]);
if (size == 0) {
break;
}
}
Err(e) => break,
};
}
let req = std::str::from_utf8(&client.readed.as_slice())
.unwrap()
.to_string();
if !(req.find("\n\n").is_some() || req.find("\r\n\r\n").is_some()) {
continue;
}
let mut ev = EpollEvent::new(
EpollFlags::EPOLLOUT | EpollFlags::EPOLLET,
cur_socket as u64,
);
match epoll_ctl(epfd, EpollOp::EpollCtlMod, cur_socket, &mut ev) {
Ok(e) => {}
Err(err) => println!("Read ctl Err {:?}", err),
}
client.state = State::Write;
}
if cur_event == cur_event & EpollFlags::EPOLLOUT {
let buf = "HTTP/1.1 200 Ok\nConnection: close\nContent-Type: text/plain\n\nha?\n\n";
let buf_len = buf.len();
let mut sended = 0;
let mut need_to_close = false;
loop {
match write(cur_socket, &buf.as_bytes()[sended..]) {
Ok(len) => {
sended += len;
if sended >= buf_len {
need_to_close = true;
break;
}
}
Err(e) => {
need_to_close = true;
break;
}
}
}
if (need_to_close) {
match epoll_ctl(
epfd,
EpollOp::EpollCtlDel,
cur_socket as i32,
&mut epoll_events[i],
) {
Ok(e) => {}
Err(err) => println!("Err epollctl write {:?}", err),
}
clients.remove(&cur_socket);
match shutdown(cur_socket as i32, Shutdown::Both) {
Ok(e) => {}
Err(err) => println!("Err shutdown {:?}", err),
}
close(cur_socket as i32)?;
closed += 1;
println!("closed: {:?}", closed);
}
}
continue;
}
}
}
fn main() {
let server_sock = match socket(
AddressFamily::Inet,
SockType::Stream,
SockFlag::SOCK_NONBLOCK,
SockProtocol::Tcp,
) {
Ok(sock) => sock,
Err(err) => panic!("{:?}", err),
};
match setsockopt(server_sock, ReuseAddr, &true) {
Ok(_) => {}
Err(err) => panic!("Error set sock opt {:?}", err),
}
let addr = SockAddr::new_inet(InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 5468));
match bind(server_sock, &addr) {
Ok(_) => {}
Err(err) => panic!("Error bind: {:?}", err),
}
socket_to_nonblock(server_sock);
match listen(server_sock, 1024) {
Ok(_) => {}
Err(err) => panic!("Error listen: {:?}", err),
}
epoll_loop(server_sock.clone());
}

How do I prevent TcpStream from blocking on a read?

let listener = TcpListener::bind("localhost:1234").unwrap();
for stream in listener.incoming() {
let s = stream.unwrap();
handle_stream(s);
}
fn handle_stream(mut stream: TcpStream) -> () {
let mut buf = [0];
loop {
let _ = match stream.read(&mut buf) {
Err(e) => panic!("Got an error: {}", e),
Ok(m) => {
println!("Received {:?}, {:?}", m, buf);
if m == 0 {
// doesn't reach here.
break;
}
m
},
};
}
}
I then connect to the server by running curl http://localhost:1234.
I expect Ok(0) would be returned, but it doesn't reach that statement and it hangs instead. If that's an EOF, how can I treat in this case?
You want to use TcpStream::set_read_timeout and then check for that specific type of error:
use std::io::{self, Read};
use std::net::{TcpListener, TcpStream};
use std::time::Duration;
fn main() {
let listener = TcpListener::bind("localhost:1234").unwrap();
for stream in listener.incoming() {
let s = stream.unwrap();
handle_stream(s);
}
fn handle_stream(mut stream: TcpStream) -> () {
let mut buf = [0];
stream.set_read_timeout(Some(Duration::from_millis(100))).unwrap();
loop {
let _ = match stream.read(&mut buf) {
Err(e) => {
match e.kind() {
io::ErrorKind::WouldBlock => {
println!("would have blocked");
break;
},
_ => panic!("Got an error: {}", e),
}
},
Ok(m) => {
println!("Received {:?}, {:?}", m, buf);
if m == 0 {
// doesn't reach here.
break;
}
m
},
};
}
}
}

Resources