रूबी एप्लिकेशन सर्वर आमतौर पर nginx जैसे वेब सर्वर के साथ उपयोग किए जाते हैं। जब उपयोगकर्ता आपके रेल ऐप से किसी पृष्ठ का अनुरोध करता है, तो nginx एप्लिकेशन सर्वर को अनुरोध सौंपता है। लेकिन यह वास्तव में कैसे काम करता है? nginx गेंडा के साथ कैसे बात करता है?
सबसे कुशल विकल्पों में से एक यूनिक्स सॉकेट का उपयोग करना है। आइए देखें कि वे कैसे काम करते हैं! इस पोस्ट में हम सॉकेट की मूल बातें से शुरू करेंगे, और अपना खुद का सरल एप्लिकेशन सर्वर बनाकर समाप्त करेंगे जो कि nginx द्वारा प्रॉक्सी किया गया है।
सॉकेट प्रोग्राम को एक दूसरे के साथ बात करने की अनुमति देते हैं जैसे कि वे किसी फ़ाइल को लिख रहे हों या पढ़ रहे हों। इस उदाहरण में, यूनिकॉर्न सॉकेट बनाता है और कनेक्शन के लिए इसकी निगरानी करता है। Nginx तब सॉकेट से जुड़ सकता है और यूनिकॉर्न के साथ बात कर सकता है।
यूनिक्स सॉकेट क्या है?
यूनिक्स सॉकेट एक प्रोग्राम को दूसरे से इस तरह से बात करने देता है जो फाइलों के साथ काम करने जैसा दिखता है। वे एक प्रकार के आईपीसी, या अंतर-प्रक्रिया संचार हैं।
सॉकेट के माध्यम से पहुंच योग्य होने के लिए, आपका प्रोग्राम पहले एक सॉकेट बनाता है और उसे एक फ़ाइल की तरह डिस्क पर "सहेजता है"। यह आने वाले कनेक्शन के लिए सॉकेट की निगरानी करता है। जब यह एक प्राप्त करता है, तो यह डेटा को पढ़ने और लिखने के लिए मानक IO विधियों का उपयोग करता है।
रूबी कुछ वर्गों के माध्यम से आपको यूनिक्स सॉकेट के साथ काम करने के लिए आवश्यक सब कुछ प्रदान करती है:
-
यूनिक्स*सर्वर * - यह सॉकेट बनाता है, इसे डिस्क पर सहेजता है, और आपको नए कनेक्शन के लिए इसकी निगरानी करने देता है।
-
यूनिक्स*सॉकेट * - आईओ के लिए मौजूदा सॉकेट खोलें।
नोट: अन्य प्रकार के सॉकेट मौजूद हैं। सबसे विशेष रूप से टीसीपी सॉकेट। लेकिन यह पोस्ट केवल यूनिक्स सॉकेट से संबंधित है। आप अंतर किस तरह बताएंगे? यूनिक्स सॉकेट में फ़ाइल नाम होते हैं।
सबसे सरल सॉकेट
हम दो छोटे कार्यक्रमों को देखने जा रहे हैं।
पहला "सर्वर" है। यह केवल 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 को कॉन्फ़िगर करने की आवश्यकता है: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 के साथ-साथ अपनी स्क्रिप्ट को भी फायर करता हूं, तो मैं लोकलहोस्ट पर जा सकता हूं:2048। अनुरोध मेरे ऐप पर भेजे जाते हैं। और प्रतिक्रियाएँ ब्राउज़र द्वारा प्रदान की जाती हैं। बहुत बढ़िया!
HTTP अनुरोध हमारे सरल ऐप सर्वर द्वारा STDOUT में लॉग किए जाते हैं
और यहाँ हमारे परिश्रम का गौरवशाली फल है। निहारना! एक टाइमस्टैम्प!
सर्वर एक टाइमस्टैम्प लौटाता है जो ब्राउज़र में प्रदर्शित होता है