WebSocket في Rust: مكتبات tokio-tungstenite و tungstenite

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مكتبات 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

توصيات