जब WebSocket बहुत ज़्यादा है, या SSE फिर से क्यों लोकप्रिय है
\n\nकल्पना करें: आपको सर्वर से क्लाइंट को रीयल-टाइम में डेटा भेजना है। मुद्रा दरें, नए संदेशों की सूचनाएँ, सर्वर लॉग, फ़ाइल प्रोसेसिंग की प्रगति। सबसे पहले जो दिमाग में आता है वह है WebSocket। लेकिन क्या होगा अगर आपको दो-तरफ़ा चैनल की ज़रूरत नहीं है? क्या होगा अगर क्लाइंट केवल सुनता है, और सर्वर केवल बोलता है?
\n\nयहाँ पर Server-Sent Events (SSE) आता है — एक प्रोटोकॉल जो सर्वर को सामान्य HTTP कनेक्शन के माध्यम से क्लाइंट को डेटा भेजने की अनुमति देता है। बिना अतिरिक्त हैंडशेक के, बिना जटिल प्रोटोकॉल के, बिना प्रॉक्सी और लोड बैलेंसर्स के सिरदर्द के। और हाँ, Rust पर यह बहुत शानदार काम करता है।
\n\nइस लेख में, हम देखेंगे कि लोकप्रिय फ्रेमवर्क का उपयोग करके Rust पर SSE को शुरू से कैसे स्थापित किया जाए। आप काम करने वाले उदाहरण देखेंगे, छिपी हुई समस्याओं के बारे में जानेंगे, और समझेंगे कि SSE आपके लिए सबसे अच्छा विकल्प कब है।
\n\nServer-Sent Events क्या है और Rust क्यों?
\n\nSSE एक W3C मानक (EventSource API) है जो सर्वर को HTTP पर क्लाइंट को स्ट्रीमिंग डेटा भेजने की अनुमति देता है। क्लाइंट एक एंडपॉइंट से जुड़ता है, और सर्वर text/event-stream प्रारूप में संदेश भेजना शुरू करता है। यह सब सामान्य HTTP/1.1 या HTTP/2 पर काम करता है, विशेष प्रॉक्सी की आवश्यकता नहीं होती है, और सभी आधुनिक ब्राउज़रों द्वारा समर्थित है।
Rust क्यों? क्योंकि Rust हमें देता है:
\n- \n
- बिना आश्चर्य के एसिंक्रोनसी — Tokio और async-std एक थ्रेड पर हज़ारों SSE कनेक्शन रखने की अनुमति देते हैं \n
- मेमोरी सुरक्षा — मल्टी-थ्रेडेड स्ट्रीमिंग में कोई लीक नहीं, कोई race conditions नहीं \n
- न्यूनतम संसाधन खपत — एक SSE कनेक्शन कुछ किलोबाइट खपत करता है \n
- पारिस्थितिकी तंत्र — Actix Web, Rocket, Axum — सभी बॉक्स से बाहर या न्यूनतम एक्सटेंशन के साथ SSE का समर्थन करते हैं \n
SSE कैसे काम करता है: प्रोटोकॉल को समझना
\n\nक्लाइंट ब्राउज़र में एक URL निर्दिष्ट करके EventSource बनाता है। सर्वर Content-Type: text/event-stream हेडर के साथ जवाब देता है और निम्नलिखित प्रारूप में पंक्तियाँ भेजना शुरू करता है:
data: नमस्ते, दुनिया!\\n\\n\n\nप्रत्येक संदेश एक ब्लॉक है जहाँ data: में पेलोड होता है। संदेश दो न्यूलाइन वर्णों से अलग होते हैं। JSON, संख्याएँ, स्ट्रिंग्स — कुछ भी भेजा जा सकता है। इसके अतिरिक्त id, event और retry फ़ील्ड हैं।
यहाँ SSE संदेश का एक न्यूनतम उदाहरण है:
\n\nid: 1\nevent: update\ndata: {"status": "processing", "progress": 42}\n\n\n\nJavaScript पर क्लाइंट इसे update इवेंट के रूप में प्राप्त करता है जिसमें data फ़ील्ड में JSON होता है।
Actix Web के साथ Rust पर SSE सर्वर लिखना
\n\nचलिए सबसे लोकप्रिय फ्रेमवर्क — Actix Web से शुरू करते हैं। निर्भरताएँ स्थापित करें:
\n\n[dependencies]\nactix-web = "4"\nactix-rt = "2"\ntokio = { version = "1", features = ["full"] }\nserde = { version = "1", features = ["derive"] }\nserde_json = "1"\n\nअब एक सरल एंडपॉइंट लिखते हैं जो हर 2 सेकंड में वर्तमान समय भेजेगा:
\n\nuse actix_web::{get, web, App, HttpRequest, HttpResponse, HttpServer, middleware};\nuse actix_web::rt::time;\nuse futures::stream::StreamExt;\nuse std::time::Duration;\n\n#[get("/events")]\nasync fn stream_events(req: HttpRequest) -> HttpResponse {\n let mut rx = tokio::sync::broadcast::channel::<String>(100).1;\n\n let stream = async_stream::stream! {\n loop {\n let message = format!("data: {}\\n\\n", chrono::Local::now());\n yield Ok::<_, actix_web::Error>(\n web::Bytes::from(message)\n );\n time::sleep(Duration::from_secs(2)).await;\n }\n };\n\n HttpResponse::Ok()\n .insert_header(("Content-Type", "text/event-stream"))\n .insert_header(("Cache-Control", "no-cache"))\n .insert_header(("Connection"