Конвертация 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)
Безопасность без потери производительности