CodeBlanks Logo Icon CodeBlanks

İstemci iş parçacığı

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

main.rs
use std::io::{self, BufRead, BufReader, Write};
use std::net::{SocketAddr, TcpListener, TcpStream};
use std::thread;

fn main() {
    // buraya yaz
}

Örnek çözüm

main.rs
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ç

Soru
let mut yazici = akis.____()?;
Cevap
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

İleri seviye bölümündeki tüm dersler