İstemci iş parçacığı
- Rust kursu
- İleri seviye
- Ders 26/81
- 6 dk
Her istemci için bir thread açıp yönetirsin.
İstemci iş parçacığı
Tek bir döngüde istemcileri sırayla işlemek, yavaş bir istemcinin herkesi bekletmesi demektir. Her bağlantıyı ayrı bir thread'e vermek, istemcilerin bağımsız ilerlemesini sağlar:
for akis in dinleyici.incoming() {
let akis = akis?;
thread::spawn(move || istemci_isle(akis));
}
fn istemci_isle(akis: TcpStream) -> io::Result<()> {
let mut yazici = akis.try_clone()?;
for satir in BufReader::new(akis).lines() {
writeln!(yazici, "{}", satir?.to_uppercase())?;
}
Ok(())
}try_clone, aynı soket için ikinci bir tutamaç verir: biri okumaya, biri yazmaya.
Yankı protokolü
Protokolü test etmek için sunucu her satırı büyük harfe çevirip geri göndersin. İstemci tarafı bir satır yazar ve bir satır okur:
fn sor(adres: SocketAddr, mesaj: &str) -> io::Result<String> {
let mut akis = TcpStream::connect(adres)?;
writeln!(akis, "{mesaj}")?;
let mut yanit = String::new();
BufReader::new(akis).read_line(&mut yanit)?;
Ok(yanit.trim().to_string())
}to_uppercase Unicode kurallarını uygular: "dünya" → "DÜNYA".
Uygulama Yankı sunucusu
Sunucuyu bir thread'de çalıştır: incoming().take(2) ile iki bağlantı kabul etsin ve her birini ayrı bir thread'de istemci_isle ile işlesin. Ana thread sor fonksiyonuyla önce merhaba, sonra dünya göndersin ve yanıtları ayrı satırlara yazdırsın.
Başlangıç kodu
use std::io::{self, BufRead, BufReader, Write};
use std::net::{SocketAddr, TcpListener, TcpStream};
use std::thread;
fn main() {
// buraya yaz
}Örnek çözüm
use std::io::{self, BufRead, BufReader, Write};
use std::net::{SocketAddr, TcpListener, TcpStream};
use std::thread;
fn istemci_isle(akis: TcpStream) -> io::Result<()> {
let mut yazici = akis.try_clone()?;
for s in BufReader::new(akis).lines() {
writeln!(yazici, "{}", s?.to_uppercase())?;
}
Ok(())
}
fn sor(adres: SocketAddr, mesaj: &str) -> io::Result<String> {
let mut akis = TcpStream::connect(adres)?;
writeln!(akis, "{mesaj}")?;
let mut yanit = String::new();
BufReader::new(akis).read_line(&mut yanit)?;
Ok(yanit.trim().to_string())
}
fn main() -> io::Result<()> {
let dinleyici = TcpListener::bind("127.0.0.1:0")?;
let adres = dinleyici.local_addr()?;
thread::spawn(move || {
for akis in dinleyici.incoming().take(2) {
let akis = akis.unwrap();
thread::spawn(move || istemci_isle(akis));
}
});
println!("{}", sor(adres, "merhaba")?);
println!("{}", sor(adres, "dünya")?);
Ok(())
}Beklenen çıktı
MERHABA DÜNYA
Soru ve cevaplar
Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.
1 Her istemci için bir thread modelinin sınırı nedir?
- İkiden fazla istemci olamaz
- Mesajlar karışır
- Sınırı yoktur
- On binlerce istemcide thread başına bellek ve geçiş maliyeti büyür Doğru cevap
Açıklama: Bu ölçekte async (tokio) tercih edilir; az sayıda istemci için thread modeli basit ve yeterlidir.
2 İkinci tutamaç
let mut yazici = akis.____()?;
let mut yazici = akis.try_clone()?;
Açıklama: try_clone aynı sokete ikinci bir TcpStream verir.
3 Parça ve görevi
| Kavram | Anlamı |
|---|---|
thread::spawn(..istemci_isle) |
Bağlantı başına thread |
try_clone() |
Okuma/yazma ayrımı |
lines() |
Satır satır okuma |
incoming().take(2) |
İki bağlantı sonra dur |