Конвертация C# в Rust

C#
int port_local = 11000;

UdpClient server_local = new UdpClient(port_local);
Console.WriteLine($"UDP сервер запущен на порту {port_local}...");

IPEndPoint remoteEP_local = new IPEndPoint(IPAddress.Any, 0);
CancellationTokenSource token_local = new CancellationTokenSource();

Task serverTask_local = Task.Run(() =>
{
    while (token_local.IsCancellationRequested == false)
    {
        try
        {
            byte[] data = server_local.Receive(ref remoteEP_local);
            server_local.Send(data, data.Length, remoteEP_local);
            
            string message = Encoding.UTF8.GetString(data);
            Console.WriteLine($"Получено от {remoteEP_local}: {message}");
        }
        catch (Exception ex)
        {
            Log.ошибка(ex, "UDP serverTask");
        }
    }
});
Rust
use std::net::{UdpSocket, Ipv4Addr, SocketAddr};
use std::thread;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};

const PORT: u16 = 11000;

pub fn start_udp_server() -> Arc<AtomicBool> {
    let socket = UdpSocket::bind(("0.0.0.0", PORT))
        .expect("Не удалось привязать сокет");
    
    println!("UDP сервер запущен на порту {}", PORT);
    
    let running = Arc::new(AtomicBool::new(true));
    let running_clone = running.clone();
    
    thread::spawn(move || {
        let mut buf = [0; 1024];
        
        while running_clone.load(Ordering::Relaxed) {
            match socket.recv_from(&mut buf) {
                Ok((size, src)) => {
                    let data = &buf[..size];
                    let message = String::from_utf8_lossy(data);
                    println!("Получено от {}: {}", src, message);
                    
                    // Отправляем эхо-ответ
                    if let Err(e) = socket.send_to(data, src) {
                        eprintln!("Ошибка отправки: {}", e);
                    }
                }
                Err(e) => {
                    eprintln!("Ошибка приёма: {}", e);
                }
            }
        }
    });
    
    running
}
C#
UdpClient udp_client_local = new UdpClient();
Task clientTask_local = Task.Run(async () =>
{
    try
    {
        IPEndPoint serverEP = new IPEndPoint(IPAddress.Any, 0);
        int messageCounter = 1;
        
        while (token_local.IsCancellationRequested == false)
        {
            string message = $"Сообщение {messageCounter}";
            byte[] data = Encoding.UTF8.GetBytes(message);
            
            long start_time = Stopwatch.GetTimestamp();
            udp_client_local.Send(data, data.Length, "127.0.0.1", port_local);
            
            byte[] receivedData = udp_client_local.Receive(ref serverEP);
            TimeSpan rtt = Stopwatch.GetElapsedTime(start_time);
            
            string response = Encoding.UTF8.GetString(receivedData);
            Console.WriteLine($"Ответ от сервера: {response}  |  RTT: {rtt.TotalMilliseconds.ToString("F3")} ms  |  PING: {(rtt.TotalMilliseconds / 2).ToString("F3")} ms");
            
            messageCounter++;
            await Task.Delay(1000);
        }
    }
    catch (Exception ex)
    {
        Log.ошибка(ex, "clientTask");
    }
});
Rust
use std::net::UdpSocket;
use std::time::{Duration, Instant};
use std::thread;

pub async fn start_udp_client(running: Arc<AtomicBool>) {
    let socket = UdpSocket::bind("0.0.0.0:0")
        .expect("Не удалось создать клиентский сокет");
    
    let server_addr: SocketAddr = ("127.0.0.1", PORT).into();
    let mut message_counter = 1;
    
    while running.load(Ordering::Relaxed) {
        let message = format!("Сообщение {}", message_counter);
        let data = message.as_bytes();
        
        let start_time = Instant::now();
        
        // Отправляем сообщение
        if let Err(e) = socket.send_to(data, server_addr) {
            eprintln!("Ошибка отправки: {}", e);
            continue;
        }
        
        // Получаем ответ
        let mut buf = [0; 1024];
        match socket.recv_from(&mut buf) {
            Ok((size, _)) => {
                let rtt = start_time.elapsed();
                let response = String::from_utf8_lossy(&buf[..size]);
                
                println!("Ответ от сервера: {}  |  RTT: {:.3} ms  |  PING: {:.3} ms", 
                    response, 
                    rtt.as_millis(), 
                    rtt.as_millis() as f64 / 2.0);
            }
            Err(e) => {
                eprintln!("Ошибка приёма: {}", e);
            }
        }
        
        message_counter += 1;
        thread::sleep(Duration::from_millis(1000));
    }
}
Полный код на Rust
use std::net::{UdpSocket, SocketAddr};
use std::sync::{Arc, mpsc};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::{Duration, Instant};

const PORT: u16 = 11000;

fn main() {
    println!("Запуск UDP сервера и клиента...");
    
    let running = Arc::new(AtomicBool::new(true));
    
    // Запускаем сервер
    let server_running = start_udp_server(running.clone());
    
    // Запускаем клиент в отдельном потоке
    let client_running = running.clone();
    let client_handle = thread::spawn(move || {
        let rt = tokio::runtime::Runtime::new().unwrap();
        rt.block_on(start_udp_client(client_running));
    });
    
    println!("Нажмите Enter для остановки...");
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).unwrap();
    
    // Останавливаем сервер и клиент
    running.store(false, Ordering::Relaxed);
    
    // Ждём завершения потоков
    thread::sleep(Duration::from_secs(3));
    
    println!("Программа завершена.");
}

pub fn start_udp_server(running: Arc<AtomicBool>) -> Arc<AtomicBool> {
    let socket = UdpSocket::bind(("0.0.0.0", PORT))
        .expect("Не удалось привязать сокет");
    
    println!("UDP сервер запущен на порту {}", PORT);
    
    let server_running = running.clone();
    
    thread::spawn(move || {
        let mut buf = [0; 1024];
        
        while server_running.load(Ordering::Relaxed) {
            match socket.recv_from(&mut buf) {
                Ok((size, src)) => {
                    let data = &buf[..size];
                    let message = String::from_utf8_lossy(data);
                    println!("Получено от {}: {}", src, message);
                    
                    if let Err(e) = socket.send_to(data, src) {
                        eprintln!("Ошибка отправки: {}", e);
                    }
                }
                Err(e) => {
                    eprintln!("Ошибка приёма: {}", e);
                }
            }
        }
    });
    
    running
}

pub async fn start_udp_client(running: Arc<AtomicBool>) {
    let socket = UdpSocket::bind("0.0.0.0:0")
        .expect("Не удалось создать клиентский сокет");
    
    let server_addr: SocketAddr = ("127.0.0.1", PORT).into();
    let mut message_counter = 1;
    
    while running.load(Ordering::Relaxed) {
        let message = format!("Сообщение {}", message_counter);
        let data = message.as_bytes();
        
        let start_time = Instant::now();
        
        if let Err(e) = socket.send_to(data, server_addr) {
            eprintln!("Ошибка отправки: {}", e);
            continue;
        }
        
        let mut buf = [0; 1024];
        match socket.recv_from(&mut buf) {
            Ok((size, _)) => {
                let rtt = start_time.elapsed();
                let response = String::from_utf8_lossy(&buf[..size]);
                
                println!("Ответ от сервера: {}  |  RTT: {:.3} ms  |  PING: {:.3} ms", 
                    response, 
                    rtt.as_millis(), 
                    rtt.as_millis() as f64 / 2.0);
            }
            Err(e) => {
                eprintln!("Ошибка приёма: {}", e);
            }
        }
        
        message_counter += 1;
        thread::sleep(Duration::from_millis(1000));
    }
}
Зависимости для Cargo.toml
[dependencies] tokio = { version = "1.0", features = ["full"] }

Ключевые отличия и особенности

Управление памятью

Rust обеспечивает безопасность памяти без сборщика мусора. Вместо C# GC, Rust использует владение и заимствование для предотвращения ошибок.

Асинхронность

Вместо Task.Run из C#, Rust использует async/await с рантаймом tokio. Асинхронный код в Rust компилируется в state machine.

Обработка ошибок

Rust использует Result<T, E> вместо исключений C#. Это заставляет обрабатывать все возможные ошибки компилятором.

Производительность

Код Rust компилируется в машинный код без накладных расходов рантайма, обеспечивая производительность на уровне C/C++.

Преимущества конвертации в Rust

Нулевая стоимость абстракций
Безопасные потоки без data races
Детерминированное управление ресурсами
WebAssembly поддержка
Отличная экосистема (Cargo)
Безопасность без потери производительности
Скопировано в буфер обмена!