main.rs (4430B)
1 use std::{ 2 io::{self, Read, Result, Write}, 3 net::TcpStream, 4 }; 5 6 use ffi::Event; 7 use poll::Poll; 8 9 mod ffi; 10 mod poll; 11 12 fn get_req(path: &str) -> Vec<u8> { 13 format!( 14 "GET {path} HTTP/1.1\r\n\ 15 Host: localhost\r\n\ 16 Connection: close\r\n\ 17 \r\n" 18 ) 19 .into_bytes() 20 } 21 22 fn handle_events(events: &[Event], streams: &mut [TcpStream]) -> Result<usize> { 23 let mut handled_events = 0; 24 for event in events { 25 // We retrieve the token that identifies which TcpStream 26 // we received an event for 27 let index = event.token(); 28 let mut data = vec![0u8; 4096]; 29 30 loop { 31 match streams[index].read(&mut data) { 32 // If we get Ok(n) and the value is 0, we’ve drained the 33 // buffer; we consider the event as handled and break out 34 // of the loop. 35 Ok(0) => { 36 handled_events += 1; 37 break; 38 } 39 // If we get Ok(n) with a value larger than 0, 40 // we read the data to a String and print it out 41 // with some formatting. 42 Ok(n) => { 43 let txt = String::from_utf8_lossy(&data[..n]); 44 println!("RECEIVED: {:?}", event); 45 println!("{txt}\n------\n"); 46 } 47 // WouldBlock indicates that the data transfer is not complete, 48 // but there is no data ready right now. 49 Err(e) if e.kind() == io::ErrorKind::WouldBlock => break, 50 Err(e) => return Err(e), 51 } 52 } 53 } 54 55 Ok(handled_events) 56 } 57 58 fn main() -> Result<()> { 59 // The first thing we do is to create a new Poll instance. 60 let mut poll = Poll::new()?; 61 // We also specify what number of events we want to create 62 // and handle in our example. 63 let n_events = 5; 64 65 // The next step is creating a variable to hold a collection of 66 // Vec<TcpStream> objects. 67 let mut streams = vec![]; 68 // We also store the address to our local delayserver in 69 // a variable called addr. 70 let addr = "localhost:8090"; 71 72 // The next part is where we create a set of requests that we issue to 73 // our delayserver, which will eventually respond to us. For each request, 74 // we expect a read event to happen sometime later on in the TcpStream 75 // we sent the request on. 76 for i in 0..n_events { 77 // Setting the delay to (n_events - i) * 1000 simply sets the 78 // first request we make to have the longest timeout, 79 // so we should expect the responses to arrive in the reverse order 80 // from which they were sent. 81 let delay = (n_events - i) * 1000; 82 let url_path = format!("/{delay}/request-{i}"); 83 let request = get_req(&url_path); 84 let mut stream = std::net::TcpStream::connect(addr)?; 85 stream.set_nonblocking(true)?; 86 87 stream.write_all(&request)?; 88 poll.registry() 89 .register(&stream, i, ffi::EPOLLIN | ffi::EPOLLET)?; 90 91 streams.push(stream); 92 } 93 94 // The next part of the main function is handling incoming events: 95 // 96 // First, create a variable called handled_events to track 97 // how many events we have handled. 98 let mut handled_events = 0; 99 // We loop as long as the handled events are less than the number 100 // of events we expect. Once all events are handled, we exit the loop. 101 while handled_events < n_events { 102 // It’s important that we create this using Vec::with_capacity 103 // since the operating system will assume that we pass it 104 // memory that we’ve allocated. 105 let mut events = Vec::with_capacity(10); 106 // this will actually tell the operating system to park our thread 107 // and wake us up when an event has occurred. 108 poll.poll(&mut events, None)?; 109 110 if events.is_empty() { 111 // If we’re woken up, but there are no events in the list, 112 // it’s either a timeout or a spurious event (which could 113 // happen, so we need a way to check whether a timeout has 114 // actually elapsed if that’s important to us). 115 println!("TIMEOUT (OR SPURIOUS EVENT NOTIFICATION)"); 116 continue; 117 } 118 119 handled_events += handle_events(&events, &mut streams)?; 120 } 121 122 println!("FINISHED"); 123 Ok(()) 124 }