Rx और HttpListener का उपयोग करके C # में इवेंट-संचालित HTTP सर्वर

काफी बड़ा नाम? हाँ? इस पोस्ट में, मैं आपको प्रतिक्रियाशील एक्सटेंशन की शक्ति का उपयोग करके C # में एक सरल ईवेंट-उन्मुख HTTP सर्वर बनाने में एक वैकल्पिक दृष्टिकोण दिखाऊंगा।

परिचय

मैं समझाने में बहुत अच्छा नहीं हूं, इसलिए मैं इवेंट मॉडल नोड.जेएस के बारे में डैन यॉर्क से एक बहुत ही दिलचस्प लेख उद्धृत करूंगा:
वेब सर्वर का "पारंपरिक" मोड हमेशा स्ट्रीम मॉडल पर आधारित होता है। जब आप अपाचे या किसी अन्य वेब सर्वर को शुरू करते हैं, तो यह कनेक्शन स्वीकार करना शुरू कर देता है। जब यह एक कनेक्शन स्वीकार करता है, तो यह कनेक्शन को तब तक खुला रखता है जब तक कि यह पृष्ठ या किसी अन्य लेनदेन को संसाधित नहीं करता। यदि डिस्क से किसी पृष्ठ को पढ़ने या डेटाबेस में परिणाम लिखने में कई माइक्रोसेकंड लगते हैं, तो वेब सर्वर इनपुट / आउटपुट संचालन के लिए अवरुद्ध हो जाता है। (इसे "I / O को अवरुद्ध करना" कहा जाता है)। इस प्रकार के सर्वर को स्केल करने के लिए, आपको सर्वर की अतिरिक्त प्रतियां स्वयं चलाने की आवश्यकता होगी (जिसे "थ्रेड-बेस्ड" कहा जाता है, क्योंकि प्रत्येक कॉपी में आमतौर पर एक अतिरिक्त ऑपरेटिंग सिस्टम थ्रेड की आवश्यकता होती है)।
इसके विपरीत, Node.JS एक ईवेंट-चालित मॉडल का उपयोग करता है जिसमें वेब सर्वर अनुरोधों को स्वीकार करता है, जल्दी से उन्हें प्रसंस्करण के लिए रख देता है, और फिर अगले अनुरोध के लिए उन्हें ले जाता है। जब प्रारंभिक अनुरोध पूरा हो जाता है, तो यह प्रसंस्करण कतार में वापस आ जाता है और जब यह कतार के अंत तक पहुंच जाता है, तो परिणाम वापस आ जाते हैं (या निम्न कार्य करने के लिए आवश्यक हर चीज की आवश्यकता होती है)। यह मॉडल बहुत कुशल और स्केलेबल है, क्योंकि वेब सर्वर आमतौर पर अनुरोधों को स्वीकार करता है, क्योंकि एक भी पढ़ने या लिखने के ऑपरेशन के पूरा होने का इंतजार नहीं करता। (इस पद्धति को "गैर-अवरुद्ध I / O" या "घटना-उन्मुख I / O" कहा जाता है)।

.NET दुनिया में क्या चल रहा है?

.NET इकोसिस्टम में इसके आसपास बहुत सी चीजें होती हैं:

वैकल्पिक दृष्टिकोण

HttpListener वर्ग और प्रतिक्रियात्मक एक्सटेंशन का उपयोग करके, हम कुछ इस तरह से बना सकते हैं:
public class HttpServer : IObservable<RequestContext>, IDisposable { private readonly HttpListener listener; private readonly IObservable<RequestContext> stream; public HttpServer(string url) { listener = new HttpListener(); listener.Prefixes.Add(url); listener.Start(); stream = ObservableHttpContext(); } private IObservable<RequestContext> ObservableHttpContext() { return Observable.Create<RequestContext>(obs => Observable.FromAsyncPattern<HttpListenerContext>(listener.BeginGetContext, listener.EndGetContext)() .Select(c => new RequestContext(c.Request, c.Response)) .Subscribe(obs)) .Repeat() .Retry() .Publish() .RefCount(); } public void Dispose() { listener.Stop(); } public IDisposable Subscribe(IObserver<RequestContext> observer) { return stream.Subscribe(observer); } } 

इस कोड पर कुछ नोट:

उदाहरण का उपयोग करें

आप इस अवधारणा के आधार पर किसी भी प्रकार का वेब एप्लिकेशन बना सकते हैं। "हैलो वर्ल्ड" स्तर का एक आवेदन इस तरह दिखेगा:
 static void Main() { //a stream os messages var subject = new Subject<string>(); using(var server = new HttpServer("http://*:5555/")) { var handler = server.Where(ctx => ctx.Request.Url.EndsWith("/hello")) .Subscribe(ctx => ctx.Respond(new StringResponse("world"))); Console.ReadLine(); handler.Dispose(); } } 

मेरा सुझाव है कि आप जो भी कर रहे हैं वह अतुल्यकालिक है। उदाहरण के लिए, यदि आप किसी डेटाबेस से कनेक्ट करते हैं, तो यह एक एसिंक्रोनस ऑपरेशन होना चाहिए, और आपको कॉलबैक / वेधशाला / कार्य, आदि को एक साथ रखने की आवश्यकता होगी।

एक और भी दिलचस्प अनुप्रयोग है जिसे मैं साझा करना चाहूंगा, जिसे दीर्घ मतदान कहा जाता है:
लंबे मतदान पारंपरिक मतदान तकनीक का एक रूपांतर है और आपको सर्वर से क्लाइंट तक जानकारी भेजने का अनुकरण करने की अनुमति देता है। लंबे मतदान के साथ, क्लाइंट सामान्य अनुरोध के साथ सर्वर से उसी तरह से जानकारी का अनुरोध करता है। हालाँकि, यदि सर्वर के पास क्लाइंट के लिए कोई उपलब्ध जानकारी नहीं है, तो सर्वर खाली प्रतिक्रिया भेजने के बजाय, अनुरोध को रखता है और जानकारी उपलब्ध होने की प्रतीक्षा करता है।

इसलिए, उपरोक्त कोड के माध्यम से काम करने वाले लंबे मतदान का सबसे सरल उदाहरण है:
 class Program { static void Main() { //a stream os messages var subject = new Subject<string>(); using(var server = new HttpServer("http://*:5555/")) { //the listeners stream and subscription var listeners = server .Where(ctx => ctx.Request.HttpMethod == "GET") .Subscribe(ctx => subject.Take(1) //wait the next message to end the request .Subscribe(m => ctx.Respond(new StringResponse(m)))); //the publishing stream and subscrition var publisher = server .Where(ctx => ctx.Request.HttpMethod == "POST") .Subscribe(ctx => ctx.Request.InputStream.ReadBytes(ctx.Request.ContentLength) .Subscribe(bts => { ctx.Respond(new EmptyResponse(201)); subject.OnNext(Encoding.UTF8.GetString(bts)); })); Console.ReadLine(); listeners.Dispose(); publisher.Dispose(); } } } 

जैसा कि आप देख सकते हैं, हम पर्यवेक्षकों को काम करते हैं ... कोई ब्लॉकिंग ऑपरेशन नहीं है। यहां तक ​​कि एक धारा से पढ़ना एक अतुल्यकालिक ऑपरेशन है।

वर्किंग कोड देखना चाहते हैं?

नीचे एक वीडियो दिखाया गया है कि कोड कैसे काम करता है:
छवि
और अंत में, सोर्स कोड को ओपनसोर्स के तहत यहां प्रकाशित किया गया है यदि आप इसे चरण दर चरण में बदलना चाहते हैं या बस इसे एक्सप्लोर करें।
गुस्तावो मचाडो, सिल्वियो मस्सारी और नैंसी फ्रेमवर्क के टिप्स और कोड के भाग के लिए विशेष धन्यवाद, जो मैंने उनसे चुराया था।


Source: https://habr.com/ru/post/In129861/


All Articles