Correct use of sockets and / or Celluloid :: IO

I have a Pinoccio microcontroller (absolutely awesome, try it). The microcontroller opens a socket on it. I am writing this TCP Socket Server in a Ruby application in which I will be using Celluloid :: IO . As my guide, I am following this implementation in Node called pinoccio-server

I wrote some test code to try and communicate with the Pinoccio microcontroller. I can read from it with no problem, but when I write data back to the socket, I never get the expected behavior. Here is the code, can anyone tell me if I'm overusing Celluloid :: IO or sockets?

https://gist.github.com/roder/ab211f2f58ad6c90a3a9

+3


source to share


1 answer


At the time, if this is the question, the syntax was right. But now it's not the way out 0.17.0

of Celluloid

... but that's not the answer, it is just an introduction. I forked and edited my meaning:

https://gist.github.com/digitalextremist/7dc74b03587cd4b3b7dd

Here's the new meaning:

require 'celluloid/current'
require 'celluloid/io'
require 'json'

class TestServer
  include Celluloid::IO
  finalizer :shutdown

  def initialize(host, port)
    puts "*** Starting echo server on #{host}:#{port}"

    # Since we included Celluloid::IO, we're actually making a
    # Celluloid::IO::TCPServer here
    @server = TCPServer.new(host, port)
  end

  def shutdown
    @server.close rescue nil
  end

  def run
    loop {
      async.handle_connection(@server.accept)
    }
  end

  def handle_connection(socket)
    addr = *socket.peeraddr
    puts "*** Received connection from #{addr[3]}:#{addr[1]}"

    # This is just a test, followed this format:
    #  https://github.com/soldair/pinoccio-server/blob/master/troop.js#L163
    cmd = {
      :type => "command",
      :to => 1,
      :timeout => 10000,
      :command => "led.on"
    }
    json_cmd = "#{cmd.to_json}\n"
    socket.write json_cmd # The light never turns on. Why?
    puts json_cmd

    loop {
      puts socket.readpartial(4096)
    }
  rescue EOFError
    puts "*** #{addr[3]}:#{addr[1]} disconnected"
  rescue => ex
    echo "Trouble with socket: [#{ex.class}] #{ex.message}"
  ensure
    socket.close rescue nil
  end
end

TestServer.supervise(as: :test_server, args: ["0.0.0.0", 1234])
#de Not needed. Killed by Celluloid.shutdown already...
#de trap("INT") { supervisor.terminate; exit }

#de Avoid starting the server in the constructor, then sleeping.
#de Could end up with a race condition, and/or botch instantiation.
#de But with that being said, you need to detect crashes... so:
loop {
  begin
    Celluloid[:test_server].run
  rescue => ex
    echo "Trouble with supervised server: [#{ex.class}] #{ex.message}"
    echo "Waiting 1.26 seconds for actor to be reinstantiated."
    sleep 1.26
  end
}

      


Notable changes:



  • First, call Celluloid

    and return it correctly.
  • Do not start the server again in initialize

    .
  • Catch the death of the server and restart it after the actor is restored.
  • Become compliant with the new API.
  • Close the server tightly at the end.
  • Unplug the outlet firmly when unplugging.
  • Avoid duplicating a shutdown already started by itself Celluloid

    .
  • Avoid using a hostname that is often missing. Show numeric address.
  • Catch the type of error caused by the recording and show the reason.
  • Closing a socket will always happen, no matter how the socket dies.

The code originally started should work, or at least it should give you a clear reason why it didn't work. The above code is now compatible Celluloid

with 0.17.0

, and the same for the new Celluloid::IO

... If you have further problems, please specify the error.

Note. ... You will need to find that the server has crashed and is still holding an open port that you expect to receive, and which is not included in the example ... but the example that is listed in the test suite Celluloid::IO

:

0


source







All Articles