Comments 10
Зачем брать раст и писать на нем блокирующий сетевой код? И почему вы предлагаете спавнить поток для каждого коннекта? Это же антипаттерн.
А вы используете чатгпт, когда готовите по нескольку некачественных статей в день на разные тематики?
Да, я спросил у него пример ТСР сервера на Расте и получил точно такой же пример. Другое дело, что потом я уточнил, что потоков должно быть ровно 4 и получил вот это:
Скрытый текст
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::sync::mpsc;
use std::thread;
use std::sync::{Arc, Mutex};
const NUM_THREADS: usize = 4;
struct ThreadPool {
workers: Vec<Worker>,
sender: mpsc::Sender<Job>,
}
type Job = Box<dyn FnOnce() + Send + 'static>;
impl ThreadPool {
fn new(size: usize) -> ThreadPool {
assert!(size > 0);
let (sender, receiver) = mpsc::channel();
let receiver = Arc::new(Mutex::new(receiver));
let mut workers = Vec::with_capacity(size);
for id in 0..size {
workers.push(Worker::new(id, Arc::clone(&receiver)));
}
ThreadPool { workers, sender }
}
fn execute<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
let job = Box::new(f);
self.sender.send(job).unwrap();
}
}
struct Worker {
_id: usize,
_thread: thread::JoinHandle<()>,
}
impl Worker {
fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
let thread = thread::spawn(move || loop {
let job = receiver.lock().unwrap().recv().unwrap();
println!("Worker {} got a job; executing.", id);
job();
});
Worker {
_id: id,
_thread: thread,
}
}
}
fn handle_client(mut stream: TcpStream) {
let mut buffer = [0; 1024];
while match stream.read(&mut buffer) {
Ok(size) if size > 0 => {
stream.write(&buffer[0..size]).unwrap();
true
}
Ok(_) => false,
Err(_) => {
println!("An error occurred, terminating connection with {}", stream.peer_addr().unwrap());
false
}
} {}
}
fn main() {
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
let pool = ThreadPool::new(NUM_THREADS);
println!("Server listening on port 7878");
for stream in listener.incoming() {
match stream {
Ok(stream) => {
println!("New connection: {}", stream.peer_addr().unwrap());
pool.execute(move || {
handle_client(stream)
});
}
Err(e) => {
println!("Error: {}", e);
}
}
}
}
Так что да, программисты будут не нужны и т.д. и т.п.
А можно взять tokio и tower, что позволит выкинуть преамбулу, связанную с реализацией тредпула и воркеров, да еще и упростит main.
Глянул код свежим взглядом. Код все еще блокирующий. Решение от чатгпт предполагает удержание потока из пула на каждого клиента вплоть до закрытия соединения, блокируясь на вызове read. При исчерпании пула остальные подключения будут накапливаться в буфере mpsc.
Программисты будут еще какое-то время нужны, как минимум для верификации галлюцинаций LLM, чтобы такое случайно на прод не уехало
Этот код не будет обрабатывать больше 4 одновременно подключенных клиентов.
Вам намекают использовать async.
Del
Зачем каждый раз спавнить поток для каждого коннекта? Это ж антипаттерн, да и ресурсы так сжигаются на ура. Про асинхронный подход автор явно забыл — ведь можно было взять Tokio и легко избавиться от этого костыля с потоками. И да, весь этот подход точно не годится для продакшна
Вы общаетесь с ботом. Он (и другие смежные аккаунты) высирает по нескольку статей в день для инфоцыган из отуса, обычно это просто пересказ документации, или неработающий код от чатботов. Интересно, какая помойка у них на курсах, если статьи такие. Ну а администрацию хабра видимо всё устраивает.
Ну, объективности ради, в данном случае код - рабочий. И он гораздо проще и, главное, понятнее для новичка, чем классика из The Rust Book: https://doc.rust-lang.org/book/ch20-00-final-project-a-web-server.html
Но учить так делать, конечно, не надо. Ибо если так делать норм, то зачем Rust-то?! Он для тех, кто ресурсы хочет беречь. Тем, для кого важнее простота, лучше использовать, например, Python.
(Если что, мне лично очень нравятся и Rust, и Python, в зависимости от задач использую один или другой.)
Надеялся увидеть хорошие примеры (Tokio, async), а не это. Очень жаль.
Разбираемся с сетевым программированием на Rust