मैं यूनिकॉर्न की लाइनों के साथ एक सरल प्रीफोरिंग सर्वर को समझने और फिर से बनाने की कोशिश कर रहा हूं, जहां प्रारंभिक सर्वर पर सर्वर 4 प्रक्रियाओं को नियंत्रित करता है जो सभी नियंत्रण सॉकेट पर प्रतीक्षा (स्वीकार करने के लिए) करते हैं।रूबी रीडपार्टियल और read_nonblock फेंक नहीं EOFError
नियंत्रण सॉकेट @control_socket
9 7 9 9 से बांधता है और 4 श्रमिकों को उत्पन्न करता है जो कनेक्शन स्वीकार करने के लिए प्रतीक्षा करते हैं। काम प्रत्येक कार्यकर्ता पर किया के रूप में
def spawn_child
fork do
$STDOUT.puts "Forking child #{Process.pid}"
loop do
@client = @control_socket.accept
loop do
request = gets
if request
respond(@inner_app.call(request))
else
$STDOUT.puts("No Request")
@client.close
end
end
end
end
end
मैं जो केवल स्थिति कोड 200 और पाठ/html की सामग्री प्रकार के साथ एक स्ट्रिंग रिटर्न एक बहुत ही सरल रैक एप्लिकेशन का उपयोग किया है इस प्रकार है।
समस्या मैं का सामनाहै कि मेरे सर्वर के रूप में यह होना चाहिए जब मैं आने वाले अनुरोधों को पढ़ ("http://localhost:9799" में यूआरएल को हिट करके) काम करता है की तरह read
या read_partial
या read_nonblock
कुछ बजाय एक gets
का उपयोग कर रहा है। जब मैं गैर अवरोधन का उपयोग करता हूं तो यह कभी भी EOFError को फेंकने लगता है, जो मेरी समझ के अनुसार है कि इसे EOF
स्थिति प्राप्त नहीं होती है।
इससे पूरा होने के लिए loop
पढ़ने का कारण बनता है। यहां कोड स्निपेट है जो इस काम का थोड़ा सा काम करता है।
# Reads a file using IO.read_nonblock
# Returns end of file when using get but doesn't seem to return
# while using read_nonblock or readpartial
# The fact that the method is named gets is just bad naming, please ignore
def gets
buffer = ""
i =0
loop do
puts "loop #{i}"
i += 1
begin
buffer << @client.read_nonblock(READ_CHUNK)
puts "buffer is #{buffer}"
rescue Errno::EAGAIN => e
puts "#{e.message}"
puts "#{e.backtrace}"
IO.select([@client])
retry
rescue EOFError
$STDOUT.puts "-" * 50
puts "request data is #{buffer}"
$STDOUT.puts "-" * 50
break
end
end
puts "returning buffer"
buffer
end
हालांकि कोड पूरी तरह से काम करता है अगर मैं एक साधारण gets
बजाय का उपयोग read
या read_nonblock
की या यदि एक break
साथ IO.select([@client])
बदलें।
यहां कोड कोड काम करता है और प्रतिक्रिया देता है। Read_nonblock का उपयोग करने का मेरा कारण यह है कि यूनिकॉर्न kgio लाइब्रेरी का उपयोग करके बराबर का उपयोग करता है जो एक गैर-अवरुद्ध पढ़ने को लागू करता है।
def gets
@client.gets
end
पूरा कोड अगला चिपकाया गया है।
require 'socket' require 'builder' require 'rack' require 'pry' module Server class Prefork # line break CRLF = "\r\n" # number of workers process to fork CONCURRENCY = 4 # size of each non_blocking read READ_CHUNK = 1024 $STDOUT = STDOUT $STDOUT.sync # creates a control socket which listens to port 9799 def initialize(port = 21) @control_socket = TCPServer.new(9799) puts "Starting server..." trap(:INT) { exit } end # Reads a file using IO.read_nonblock # Returns end of file when using get but doesn't seem to return # while using read_nonblock or readpartial def gets buffer = "" i =0 loop do puts "loop #{i}" i += 1 begin buffer << @client.read_nonblock(READ_CHUNK) puts "buffer is #{buffer}" rescue Errno::EAGAIN => e puts "#{e.message}" puts "#{e.backtrace}" IO.select([@client]) retry rescue EOFError $STDOUT.puts "-" * 50 puts "request data is #{buffer}" $STDOUT.puts "-" * 50 break end end puts "returning buffer" buffer end # responds with the data and closes the connection def respond(data) puts "request 2 Data is #{data.inspect}" status, headers, body = data puts "message is #{body}" buffer = "HTTP/1.1 #{status}\r\n" \ "Date: #{Time.now.utc}\r\n" \ "Status: #{status}\r\n" \ "Connection: close\r\n" headers.each {|key, value| buffer << "#{key}: #{value}\r\n"} @client.write(buffer << CRLF) body.each {|chunk| @client.write(chunk)} ensure $STDOUT.puts "*" * 50 $STDOUT.puts "Closing..." @client.respond_to?(:close) and @client.close end # The main method which triggers the creation of workers processes # The workers processes all wait to accept the socket on the same # control socket allowing the kernel to do the load balancing. # # Working with a dummy rack app which returns a simple text message # hence the config.ru file read. def run # copied from unicorn-4.2.1 # refer unicorn.rb and lib/unicorn/http_server.rb raw_data = File.read("config.ru") app = "::Rack::Builder.new {\n#{raw_data}\n}.to_app" @inner_app = eval(app, TOPLEVEL_BINDING) child_pids = [] CONCURRENCY.times do child_pids << spawn_child end trap(:INT) { child_pids.each do |cpid| begin Process.kill(:INT, cpid) rescue Errno::ESRCH end end exit } loop do pid = Process.wait puts "Process quit unexpectedly #{pid}" child_pids.delete(pid) child_pids << spawn_child end end # This is where the real work is done. def spawn_child fork do $STDOUT.puts "Forking child #{Process.pid}" loop do @client = @control_socket.accept loop do request = gets if request respond(@inner_app.call(request)) else $STDOUT.puts("No Request") @client.close end end end end end end end p = Server::Prefork.new(9799) p.run
किसी क्यों पढ़ता है 'read_partial' या 'read_nonblock' या 'पढ़ा' के साथ विफल मुझे समझा जा सका। मैं वास्तव में इस पर कुछ मदद की सराहना करता हूं।
धन्यवाद।
आपके द्वारा वर्णित व्यवहार 'EOFError', 'read_nonblock' आदि के दस्तावेज़ों के विपरीत है। 'get'' वापस लौटना चाहिए, 'read_nonblock'' EOFError 'को बढ़ाया जाना चाहिए। –
क्या होता है यदि आप केवल एक ही कार्यकर्ता शुरू करते हैं? यह मेरे लिए अजीब बात है कि आप '' '' spawn_child'''' विधि में एक आवृत्ति चर '' '' क्लाइंट '''' असाइन करते हैं। क्या प्रत्येक कर्मचारी उस चर को ओवरराइड नहीं करेगा? या, कांटा अपने स्वयं के संदर्भ स्थापित करता है? – GSP