रूबी एप्लिकेशन सर्वर आमतौर पर Nginx जैसे वेब सर्वर के साथ उपयोग किए जाते हैं। जब कोई उपयोगकर्ता आपके रेल्स ऐप से कोई पेज अनुरोध करता है, तो Nginx अनुरोध को एप्लिकेशन सर्वर को सौंप देता है। लेकिन वास्तव में यह कैसे काम करता है? Nginx यूनिकॉर्न से कैसे बात करता है?
सबसे कुशल विकल्पों में से एक है यूनिक्स सॉकेट का उपयोग करना। आइए देखें कि वे कैसे काम करते हैं! इस पोस्ट में हम सॉकेट की मूल बातें से शुरू करेंगे, और Nginx द्वारा प्रॉक्सी किए गए अपने स्वयं के सरल एप्लिकेशन सर्वर को बनाने तक जाएंगे।
सॉकेट प्रोग्राम को एक-दूसरे से बात करने की अनुमति देते हैं जैसे कि वे किसी फाइल को लिख या पढ़ रहे हों। इस उदाहरण में, यूनिकॉर्न सॉकेट बनाता है और कनेक्शन के लिए उसकी निगरानी करता है। Nginx तब सॉकेट से कनेक्ट हो सकता है और यूनिकॉर्न से बात कर सकता है।
यूनिक्स सॉकेट क्या है?
यूनिक्स सॉकेट एक प्रोग्राम को दूसरे से इस तरह बात करने देता है जो फाइलों के साथ काम करने जैसा दिखता है। वे IPC, या इंटर-प्रोसेस कम्युनिकेशन का एक प्रकार हैं।
सॉकेट के माध्यम से सुलभ होने के लिए, आपका प्रोग्राम पहले एक सॉकेट बनाता है और इसे डिस्क पर "सेव" करता है, बिल्कुल एक फाइल की तरह। यह आने वाले कनेक्शन के लिए सॉकेट की निगरानी करता है। जब यह एक प्राप्त करता है, तो यह डेटा पढ़ने और लिखने के लिए मानक IO मेथड का उपयोग करता है।
रूबी आपको कुछ क्लास के माध्यम से यूनिक्स सॉकेट के साथ काम करने के लिए आवश्यक सब कुछ प्रदान करता है:
UNIXServer - यह सॉकेट बनाता है, इसे डिस्क पर सेव करता है, और आपको नए कनेक्शन के लिए इसकी निगरानी करने देता है।
UNIXSocket - IO के लिए मौजूदा सॉकेट खोलें।
नोट: अन्य प्रकार के सॉकेट भी मौजूद हैं। सबसे विशेष रूप से TCP सॉकेट। लेकिन यह पोस्ट केवल यूनिक्स सॉकेट से संबंधित है। आप अंतर कैसे बताते हैं? यूनिक्स सॉकेट के फाइल नाम होते हैं।
सबसे सरल सॉकेट
हम दो छोटे प्रोग्राम देखने जा रहे हैं।
पहला "सर्वर" है। यह बस UnixServer क्लास का एक इंस्टेंस बनाता है, फिर कनेक्शन की प्रतीक्षा करने के लिए server.accept का उपयोग करता है। जब यह एक कनेक्शन प्राप्त करता है, तो यह एक अभिवादन का आदान-प्रदान करता है।
यह ध्यान देने योग्य है कि accept और readline दोनों मेथड प्रोग्राम निष्पादन को तब तक ब्लॉक करते हैं जब तक वे जिस चीज की प्रतीक्षा कर रहे हैं उसे प्राप्त नहीं कर लेते।
require "socket" server = UNIXServer.new('/tmp/simple.sock') puts "==== Waiting for connection" socket = server.accept puts "==== Got Request:" puts socket.readline puts "==== Sending Response" socket.write("I read you loud and clear, good buddy!") socket.close
तो हमारे पास एक सर्वर है। अब हमें बस एक क्लाइंट चाहिए।
नीचे दिए गए उदाहरण में, हम अपने सर्वर द्वारा बनाए गए सॉकेट को खोलते हैं। फिर हम अभिवादन भेजने और प्राप्त करने के लिए सामान्य IO मेथड का उपयोग करते हैं।
require "socket" socket = UNIXSocket.new('/tmp/simple.sock') puts "==== Sending" socket.write("Hello server, can you hear me?\n") puts "==== Getting Response" puts socket.readline socket.close
प्रदर्शित करने के लिए, हमें पहले सर्वर चलाना होगा। फिर हम क्लाइंट चलाते हैं। आप नीचे परिणाम देख सकते हैं:
एक साधारण UNIX सॉकेट क्लाइंट/सर्वर इंटरैक्शन का उदाहरण। क्लाइंट बाईं ओर है। सर्वर दाईं ओर है।
Nginx के साथ इंटरफेसिंग
अब जब हम जानते हैं कि यूनिक्स सॉकेट "सर्वर" कैसे बनाया जाता है, तो हम आसानी से Nginx के साथ इंटरफेस कर सकते हैं।
मेरी बात पर विश्वास नहीं होता? आइए एक त्वरित प्रूफ-ऑफ-कॉन्सेप्ट करते हैं। मैं उपरोक्त कोड को अनुकूलित करने जा रहा हूँ ताकि यह वह सब कुछ प्रिंट करे जो इसे सॉकेट से प्राप्त होता है।
require "socket" # Create the socket and "save it" to the file system server = UNIXServer.new('/tmp/socktest.sock') # Wait until for a connection (by nginx) socket = server.accept # Read everything from the socket while line = socket.readline puts line.inspect end socket.close
अब अगर मैं Nginx को /tmp/socktest.sock पर सॉकेट पर अनुरोध अग्रेषित करने के लिए कॉन्फिगर करता हूँ तो मैं देख सकता हूँ कि Nginx क्या डेटा भेज रहा है। (चिंता न करें, हम एक मिनट में कॉन्फिगरेशन पर चर्चा करेंगे)
जब मैं एक वेब अनुरोध करता हूँ, तो Nginx निम्नलिखित डेटा को मेरे छोटे सर्वर पर भेजता है:

बहुत अच्छा! यह केवल कुछ अतिरिक्त हेडर के साथ एक सामान्य HTTP अनुरोध है। अब हम एक वास्तविक ऐप सर्वर बनाने के लिए तैयार हैं। लेकिन पहले, आइए Nginx कॉन्फिगरेशन पर चर्चा करें।
Nginx इंस्टॉल और कॉन्फिगर करना
यदि आपके विकास मशीन पर Nginx पहले से इंस्टॉल नहीं है, तो एक सेकंड लें और अभी करें। होमब्रू के माध्यम से OSX पर यह वास्तव में आसान है:
brew install nginx
अब हमें Nginx को localhost:2048 पर अनुरोधों को /tmp/socktest.sock नामक सॉकेट के माध्यम से एक अपस्ट्रीम सर्वर पर अग्रेषित करने के लिए कॉन्फिगर करने की आवश्यकता है। वह नाम कुछ खास नहीं है। इसे केवल हमारे वेब सर्वर द्वारा उपयोग किए जाने वाले सॉकेट नाम से मेल खाने की आवश्यकता है।
आप इस कॉन्फिगरेशन को /tmp/nginx.conf पर सहेज सकते हैं और फिर इसे लोड करने के लिए nginx -c /tmp/nginx.conf कमांड के साथ Nginx चला सकते हैं।
# Run nginx as a normal console program, not as a daemon daemon off; # Log errors to stdout error_log /dev/stdout info; events {} # Boilerplate http { # Print the access log to stdout access_log /dev/stdout; # Tell nginx that there's an external server called @app living at our socket upstream app { server unix:/tmp/socktest.sock fail_timeout=0; } server { # Accept connections on localhost:2048 listen 2048; server_name localhost; # Application root root /tmp; # If a path doesn't exist on disk, forward the request to @app try_files $uri/index.html $uri @app; # Set some configuration options on requests forwarded to @app location @app { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_pass https://app; } } }
यह कॉन्फिगरेशन Nginx को एक सामान्य टर्मिनल ऐप की तरह चलाता है, डेमॉन की तरह नहीं। यह सभी लॉग को stdout पर भी लिखता है। जब आप Nginx चलाते हैं तो यह कुछ इस तरह दिखना चाहिए:
Nginx नॉन-डेमॉन मोड में चल रहा है।
एक DIY एप्लिकेशन सर्वर
अब जब हमने देखा है कि Nginx को अपने प्रोग्राम से कैसे जोड़ा जाए, तो एक साधारण एप्लिकेशन सर्वर बनाना काफी सरल है। जब Nginx हमारे सॉकेट पर अनुरोध अग्रेषित करता है तो यह एक मानक HTTP अनुरोध होता है। थोड़ी छेड़छाड़ के बाद मैं यह निर्धारित करने में सक्षम था कि यदि सॉकेट एक वैध HTTP प्रतिक्रिया लौटाता है, तो यह ब्राउज़र में प्रदर्शित होगा।
नीचे दिया गया एप्लिकेशन किसी भी अनुरोध को लेता है और एक टाइमस्टैम्प प्रदर्शित करता है।
require "socket" # Connection creates the socket and accepts new connections class Connection attr_accessor :path def initialize(path:) @path = path File.unlink(path) if File.exists?(path) end def server @server ||= UNIXServer.new(@path) end def on_request socket = server.accept yield(socket) socket.close end end # AppServer logs incoming requests and renders a view in response class AppServer attr_reader :connection attr_reader :view def initialize(connection:, view:) @connection = connection @view = view end def run while true connection.on_request do |socket| while (line = socket.readline) != "\r\n" puts line end socket.write(view.render) end end end end # TimeView simply provides the HTTP response class TimeView def render %[HTTP/1.1 200 OK The current timestamp is: #{ Time.now.to_i } ] end end AppServer.new(connection: Connection.new(path: '/tmp/socktest.sock'), view: TimeView.new).run
अब अगर मैं Nginx के साथ-साथ अपनी स्क्रिप्ट को चालू करता हूँ, तो मैं localhost:2048 पर जा सकता हूँ। अनुरोध मेरे ऐप को भेजे जाते हैं। और प्रतिक्रियाएँ ब्राउज़र द्वारा रेंडर की जाती हैं। बहुत बढ़िया!
HTTP अनुरोध हमारे सरल ऐप सर्वर द्वारा STDOUT पर लॉग किए गए
और यहाँ हमारे परिश्रम का शानदार फल है। निहारें! एक टाइमस्टैम्प!
सर्वर एक टाइमस्टैम्प लौटाता है जो ब्राउज़र में प्रदर्शित होता है