مكتبات WebSocket لـ Rust: tungstenite و tokio-tungstenite
WebSocket هو بروتوكول يوفر اتصالاً ثنائي الاتجاه بالكامل بين العميل والخادم عبر اتصال TCP واحد. في نظام Rust البيئي، المكتبات الأكثر شيوعًا للعمل مع WebSocket هي tungstenite (متزامنة) و tokio-tungstenite (غير متزامنة تعتمد على Tokio). توفر كلتا المكتبتين واجهة برمجة تطبيقات عالية المستوى لإنشاء خوادم وعملاء WebSocket، وتدعمان الامتدادات القياسية والأمان عبر TLS.
الميزات الرئيسية
- tungstenite: تنفيذ متزامن لـ WebSocket (RFC 6455)، يدعم العمليات المحظورة، ومناسب للنصوص البرمجية البسيطة والتضمين.
- tokio-tungstenite: غلاف غير متزامن فوق tungstenite، يتكامل مع بيئة تشغيل Tokio، ويسمح بمعالجة آلاف الاتصالات في وقت واحد.
- دعم الإطارات، الرسائل، ping/pong، وإغلاق الاتصال.
- العمل مع TLS (عبر
rustlsأوnative-tls). - دعم امتدادات WebSocket (مثل ضغط permessage-deflate).
- إعداد بسيط وتبعيات قليلة.
التثبيت
أضف المكتبة إلى Cargo.toml:
[dependencies]tokio-tungstenite = "0.21" # الخيار غير المتزامنtungstenite = "0.21" # الخيار المتزامنtokio = { version = "1", features = ["full"] } # لـ tokio-tungsteniteمثال لخادم WebSocket غير متزامن (tokio-tungstenite)
لنقم بإنشاء خادم صدى بسيط يستقبل الرسائل النصية ويعيد إرسالها:
use tokio::net::TcpListener;use tokio_tungstenite::accept_async;use tokio_tungstenite::tungstenite::Message;use futures_util::{SinkExt, StreamExt};
#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let listener = TcpListener::bind("127.0.0.1:9001").await?; println!("خادم WebSocket قيد التشغيل على ws://127.0.0.1:9001");
while let Ok((stream, peer)) = listener.accept().await { tokio::spawn(handle_connection(stream, peer)); } Ok(())}
async fn handle_connection(stream: tokio::net::TcpStream, peer: std::net::SocketAddr) { let ws_stream = match accept_async(stream).await { Ok(ws) => ws, Err(e) => { eprintln!("خطأ في الاتصال بـ {}: {}", peer, e); return; } };
let (mut write, mut read) = ws_stream.split(); println!("اتصال جديد: {}", peer);
while let Some(msg) = read.next().await { match msg { Ok(Message::Text(text)) => { println!("تم الاستلام من {}: {}", peer, text); if let Err(e) = write.send(Message::Text(text.into())).await { eprintln!("خطأ في الإرسال: {}", e); break; } } Ok(Message::Close(_)) => { println!("العميل {} قطع الاتصال", peer); break; } Err(e) => { eprintln!("خطأ: {}", e); break; } _ => {} // تجاهل الرسائل الثنائية والتحكم } }}مثال لعميل WebSocket متزامن (tungstenite)
عميل بسيط يتصل بالخادم ويرسل رسالة:
use tungstenite::{connect, Message};use url::Url;
fn main() -> Result<(), Box<dyn std::error::Error>> { let url = Url::parse("ws://echo.websocket.org")?; let (mut socket, response) = connect(url)?;
println!("تم الاتصال بالخادم"); println!("حالة HTTP: {}", response.status());
socket.send(Message::Text("مرحباً، WebSocket!".into()))?; println!("تم إرسال الرسالة");
let msg = socket.read()?; if let Message::T