Rust
Broadcast
Write to all clients through a Vec<TcpStream>.
Broadcast
When a message arrives, it must be forwarded to everyone except the sender. Separating the broadcast logic from the network makes testing easy: let the function write to any list of Writes. On the real server the list is made of TcpStreams, in a test of Vec<u8> buffers:
fn yayinla<W: Write>(istemciler: &mut [W], gonderen: usize, mesaj: &str) {
for (i, w) in istemciler.iter_mut().enumerate() {
if i != gonderen {
let _ = writeln!(w, "{mesaj}"); // a dropped client shouldn't stop everyone
}
}
}
In-memory testing
Since Vec<u8> implements Write, we can try the broadcast without a network:
let mut tamponlar: Vec<Vec<u8>> = vec![Vec::new(); 3];
yayinla(&mut tamponlar, 0, "ece: selam");
for (i, t) in tamponlar.iter().enumerate() {
let metin = String::from_utf8_lossy(t);
println!("{i}: {}", if metin.is_empty() { "-" } else { metin.trim() });
}
This is a small example of separating business logic from I/O (a sans-IO design).
Exercise Broadcast
Write the generic yayinla function above. Broadcast the message ece: selam from sender 0 to three Vec<u8> buffers and print each buffer as i: content (- if empty).
Show example solution
use std::io::Write;
fn yayinla<W: Write>(istemciler: &mut [W], gonderen: usize, mesaj: &str) {
for (i, w) in istemciler.iter_mut().enumerate() {
if i != gonderen {
let _ = writeln!(w, "{mesaj}");
}
}
}
fn main() {
let mut tamponlar: Vec<Vec<u8>> = vec![Vec::new(); 3];
yayinla(&mut tamponlar, 0, "ece: selam");
for (i, t) in tamponlar.iter().enumerate() {
let metin = String::from_utf8_lossy(t);
println!("{}: {}", i, if metin.is_empty() { "-" } else { metin.trim() });
}
}
Test yourself
-
Why ignore the write error instead of propagating it with <code>?</code>?
- The compiler forces it
- It prevents others from missing the message because of one disconnected client
- Errors don't matter
- Write returns no errors
Show answer
It prevents others from missing the message because of one disconnected client — On a real server, clients failing to write are marked for removal from the list.
-
Except the sender
for (i, w) in istemciler.iter_mut().enumerate() {
if i ____ gonderen {
let _ = writeln!(w, "{mesaj}");
}
}
Show answer
for (i, w) in istemciler.iter_mut().enumerate() {
if i != gonderen {
let _ = writeln!(w, "{mesaj}");
}
}
-
Client and what it receives (sender 0)
- 0
- -
- 1
- ece: selam
- writeln! error
- Ignored
- Vec<u8>
- Implements Write
Next lesson: Arc<Mutex> state