cztop 1.1.2 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CHANGES.md +15 -0
 - data/cztop.gemspec +3 -4
 - data/lib/cztop/actor.rb +26 -22
 - data/lib/cztop/certificate.rb +19 -11
 - data/lib/cztop/message.rb +3 -3
 - data/lib/cztop/send_receive_methods.rb +35 -6
 - data/lib/cztop/socket/types.rb +18 -0
 - data/lib/cztop/version.rb +1 -1
 - data/lib/cztop/zsock_options.rb +10 -2
 - metadata +4 -48
 - data/.github/workflows/coverage.yml +0 -20
 - data/.github/workflows/draft_api.yml +0 -27
 - data/.github/workflows/stable_api.yml +0 -26
 - data/.gitignore +0 -10
 - data/.projections.json +0 -4
 - data/.rspec +0 -2
 - data/.rubocop.yml +0 -175
 - data/.yardopts +0 -1
 - data/Rakefile +0 -6
 - data/ci/install-libczmq +0 -22
 - data/ci/install-libzmq +0 -22
 - data/examples/ruby_actor/actor.rb +0 -100
 - data/examples/simple_req_rep/rep.rb +0 -12
 - data/examples/simple_req_rep/req.rb +0 -35
 - data/examples/taxi_system/.gitignore +0 -2
 - data/examples/taxi_system/Makefile +0 -2
 - data/examples/taxi_system/README.gsl +0 -115
 - data/examples/taxi_system/README.md +0 -276
 - data/examples/taxi_system/broker.rb +0 -97
 - data/examples/taxi_system/client.rb +0 -34
 - data/examples/taxi_system/generate_keys.rb +0 -24
 - data/examples/taxi_system/start_broker.sh +0 -2
 - data/examples/taxi_system/start_clients.sh +0 -11
 - data/examples/weather_pub_sub/pub.rb +0 -24
 - data/examples/weather_pub_sub/sub.rb +0 -33
 - data/perf/README.md +0 -80
 - data/perf/inproc_lat.rb +0 -49
 - data/perf/inproc_thru.rb +0 -42
 - data/perf/local_lat.rb +0 -35
 - data/perf/remote_lat.rb +0 -26
 
| 
         @@ -1,276 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # Taxi System
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            Suppose you're running a taxi company. You have a set of taxi drivers
         
     | 
| 
       4 
     | 
    
         
            -
            working for you.  You'd like to connect them to your central server, so they're
         
     | 
| 
       5 
     | 
    
         
            -
            ready to get service requests from customers who'd like to get picked up by a
         
     | 
| 
       6 
     | 
    
         
            -
            taxi from some place X. As soon as a customer sends his service request, the
         
     | 
| 
       7 
     | 
    
         
            -
            central server will send the closest taxi nearby that's available to the
         
     | 
| 
       8 
     | 
    
         
            -
            customer.
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
            Of course you want the communication between the broker and the taxi drivers to
         
     | 
| 
       11 
     | 
    
         
            -
            be secure, meaning you want encryption and authentication.
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
            You also want ping-pong heartbeating, as you want to have confidence you can
         
     | 
| 
       14 
     | 
    
         
            -
            get in touch with your taxi drivers any time you want. And if a service
         
     | 
| 
       15 
     | 
    
         
            -
            request can't be delivered to a particular taxi driver, you wanna know
         
     | 
| 
       16 
     | 
    
         
            -
            immediately.
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
            This solution is implemented using CLIENT/SERVER sockets and the CURVE
         
     | 
| 
       19 
     | 
    
         
            -
            security mechanism.
         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
            ## Broker
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
            Here's a possible implementation of the broker. What you'll have to provide
         
     | 
| 
       24 
     | 
    
         
            -
            are the environment variables `BROKER_ADDRESS` (the public TCP endpoint),
         
     | 
| 
       25 
     | 
    
         
            -
            `BROKER_CERT` (path to the broker's secret+public keys), and `CLIENT_CERTS`
         
     | 
| 
       26 
     | 
    
         
            -
            (directory to taxi drivers' certificates, public keys only).
         
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
            After the start, the broker will just start listening for the drivers (CLIENT
         
     | 
| 
       29 
     | 
    
         
            -
            sockets) to connect. After a driver has connected, authenticated, and sent its
         
     | 
| 
       30 
     | 
    
         
            -
            `HELLO` message, the broker answers with a `WELCOME` or `WELCOMEBACK` message,
         
     | 
| 
       31 
     | 
    
         
            -
            depending if the driver was connected before (it might have reconnected and
         
     | 
| 
       32 
     | 
    
         
            -
            been assigned a new routing ID).
         
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
            The broker will present you with a Pry shell. Right before starting the shell,
         
     | 
| 
       35 
     | 
    
         
            -
            there's a small usage information, but it's not very well visible due to Pry's
         
     | 
| 
       36 
     | 
    
         
            -
            noisy start. It's simple, though. Inside that shell, you can use the method
         
     | 
| 
       37 
     | 
    
         
            -
            `#send_command(driver, command)`. Example:
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
            ```
         
     | 
| 
       40 
     | 
    
         
            -
              pry> send_command("driver1", "foobar")
         
     | 
| 
       41 
     | 
    
         
            -
            ```
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
            Depending on whether the driver is connected, it'll send the message or report
         
     | 
| 
       44 
     | 
    
         
            -
            that it cannot do so.
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       47 
     | 
    
         
            -
            #!/usr/bin/env ruby
         
     | 
| 
       48 
     | 
    
         
            -
            require 'pry'
         
     | 
| 
       49 
     | 
    
         
            -
            require 'pathname'
         
     | 
| 
       50 
     | 
    
         
            -
            require 'cztop'
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
            endpoint = ENV["BROKER_ADDRESS"]
         
     | 
| 
       53 
     | 
    
         
            -
            broker_cert = CZTop::Certificate.load ENV["BROKER_CERT"] # secret+public
         
     | 
| 
       54 
     | 
    
         
            -
            client_certs = ENV["CLIENT_CERTS"] # /path/to/client_certs/
         
     | 
| 
       55 
     | 
    
         
            -
            drivers = Pathname.new(client_certs).children.map(&:basename).map(&:to_s)
         
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
            authenticator = CZTop::Authenticator.new
         
     | 
| 
       58 
     | 
    
         
            -
            authenticator.verbose!
         
     | 
| 
       59 
     | 
    
         
            -
            authenticator.curve(client_certs)
         
     | 
| 
       60 
     | 
    
         
            -
             
     | 
| 
       61 
     | 
    
         
            -
            # create and bind socket
         
     | 
| 
       62 
     | 
    
         
            -
            @socket = CZTop::Socket::SERVER.new
         
     | 
| 
       63 
     | 
    
         
            -
            @socket.CURVE_server!(broker_cert)
         
     | 
| 
       64 
     | 
    
         
            -
            #socket.options.sndtimeo = 0
         
     | 
| 
       65 
     | 
    
         
            -
            @socket.options.heartbeat_ivl     = 100#ms
         
     | 
| 
       66 
     | 
    
         
            -
            @socket.options.heartbeat_timeout = 300#ms
         
     | 
| 
       67 
     | 
    
         
            -
            @socket.bind(endpoint)
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
            puts ">>> Socket bound to #{endpoint.inspect}"
         
     | 
| 
       70 
     | 
    
         
            -
             
     | 
| 
       71 
     | 
    
         
            -
            # get and print socket events
         
     | 
| 
       72 
     | 
    
         
            -
            Thread.new do
         
     | 
| 
       73 
     | 
    
         
            -
              monitor = CZTop::Monitor.new(@socket)
         
     | 
| 
       74 
     | 
    
         
            -
              monitor.listen("ALL")
         
     | 
| 
       75 
     | 
    
         
            -
              monitor.start
         
     | 
| 
       76 
     | 
    
         
            -
              while msg = monitor.next
         
     | 
| 
       77 
     | 
    
         
            -
                puts ">>> Socket event: #{msg.inspect}"
         
     | 
| 
       78 
     | 
    
         
            -
              end
         
     | 
| 
       79 
     | 
    
         
            -
            end
         
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
       81 
     | 
    
         
            -
            # receive messages from drivers
         
     | 
| 
       82 
     | 
    
         
            -
            @driver_map = {} # driver name => routing ID
         
     | 
| 
       83 
     | 
    
         
            -
            Thread.new do
         
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
              # CZTop::Loop (zloop) doesn't work with SERVER sockets :(
         
     | 
| 
       86 
     | 
    
         
            -
              poller = CZTop::Poller.new(@socket)
         
     | 
| 
       87 
     | 
    
         
            -
              while true
         
     | 
| 
       88 
     | 
    
         
            -
                puts "waiting for socket to become readable ..."
         
     | 
| 
       89 
     | 
    
         
            -
                socket = poller.wait
         
     | 
| 
       90 
     | 
    
         
            -
                puts "socket is readable"
         
     | 
| 
       91 
     | 
    
         
            -
                msg = socket.receive
         
     | 
| 
       92 
     | 
    
         
            -
                puts "got message"
         
     | 
| 
       93 
     | 
    
         
            -
                command, argument = msg[0].split("\t", 2)
         
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
                case command
         
     | 
| 
       96 
     | 
    
         
            -
                when "HELLO"
         
     | 
| 
       97 
     | 
    
         
            -
                  driver = argument
         
     | 
| 
       98 
     | 
    
         
            -
                  puts ">>> Driver #{driver.inspect} has connected."
         
     | 
| 
       99 
     | 
    
         
            -
                  welcome = @driver_map.key?(driver) ? "WELCOMEBACK" : "WELCOME"
         
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
                  # remember driver's assigned message routing ID
         
     | 
| 
       102 
     | 
    
         
            -
                  @driver_map[driver] = msg.routing_id
         
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
                  # send WELCOME or WELCOMEBACK
         
     | 
| 
       105 
     | 
    
         
            -
                  rep = CZTop::Message.new(welcome)
         
     | 
| 
       106 
     | 
    
         
            -
                  rep.routing_id = @driver_map[driver]
         
     | 
| 
       107 
     | 
    
         
            -
                  socket << rep
         
     | 
| 
       108 
     | 
    
         
            -
                  puts ">>> Sent #{welcome.inspect} to #{driver.inspect}"
         
     | 
| 
       109 
     | 
    
         
            -
                end
         
     | 
| 
       110 
     | 
    
         
            -
              end
         
     | 
| 
       111 
     | 
    
         
            -
            end
         
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
            def send_command(driver, command)
         
     | 
| 
       114 
     | 
    
         
            -
              if command.nil? || command.empty?
         
     | 
| 
       115 
     | 
    
         
            -
                puts "!!! No message given."
         
     | 
| 
       116 
     | 
    
         
            -
                return
         
     | 
| 
       117 
     | 
    
         
            -
              end
         
     | 
| 
       118 
     | 
    
         
            -
              if not @driver_map.key?(driver)
         
     | 
| 
       119 
     | 
    
         
            -
                puts "!!! Driver #{driver.inspect} has never connected."
         
     | 
| 
       120 
     | 
    
         
            -
                return
         
     | 
| 
       121 
     | 
    
         
            -
              end
         
     | 
| 
       122 
     | 
    
         
            -
              puts ">>> Sending message to #{driver.inspect} ..."
         
     | 
| 
       123 
     | 
    
         
            -
              msg = CZTop::Message.new(command)
         
     | 
| 
       124 
     | 
    
         
            -
              msg.routing_id = @driver_map[driver]
         
     | 
| 
       125 
     | 
    
         
            -
              @socket << msg
         
     | 
| 
       126 
     | 
    
         
            -
            rescue SocketError
         
     | 
| 
       127 
     | 
    
         
            -
              puts "!!! Driver #{driver.inspect} isn't connected anymore."
         
     | 
| 
       128 
     | 
    
         
            -
            end
         
     | 
| 
       129 
     | 
    
         
            -
             
     | 
| 
       130 
     | 
    
         
            -
            ##
         
     | 
| 
       131 
     | 
    
         
            -
            # REPL for user to play
         
     | 
| 
       132 
     | 
    
         
            -
            #
         
     | 
| 
       133 
     | 
    
         
            -
            puts <<MSG
         
     | 
| 
       134 
     | 
    
         
            -
            You can now send messages to the drivers yourself.
         
     | 
| 
       135 
     | 
    
         
            -
            The use the method #send_command, like this:
         
     | 
| 
       136 
     | 
    
         
            -
             
     | 
| 
       137 
     | 
    
         
            -
            pry> send_command("driver1", "PICKUP\t(8.541694,47.376887)")
         
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
     | 
    
         
            -
            This should show something like this in the client.rb terminal:
         
     | 
| 
       140 
     | 
    
         
            -
             
     | 
| 
       141 
     | 
    
         
            -
              03:17:01 driver1.1 | received message: "PICKUP\t(8.541694,47.376887)"
         
     | 
| 
       142 
     | 
    
         
            -
            MSG
         
     | 
| 
       143 
     | 
    
         
            -
             
     | 
| 
       144 
     | 
    
         
            -
            binding.pry
         
     | 
| 
       145 
     | 
    
         
            -
            ```
         
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
       147 
     | 
    
         
            -
            ## Client
         
     | 
| 
       148 
     | 
    
         
            -
             
     | 
| 
       149 
     | 
    
         
            -
            Here you have to provide the environment variables `BROKER_ADDRESS` (ditto),
         
     | 
| 
       150 
     | 
    
         
            -
            `BROKER_CERT` (public key only), `CLIENT_CERT` (taxi driver's certificate
         
     | 
| 
       151 
     | 
    
         
            -
            containing the secret+public keys).
         
     | 
| 
       152 
     | 
    
         
            -
             
     | 
| 
       153 
     | 
    
         
            -
            After connecting to the broker and completing the security handshake, the
         
     | 
| 
       154 
     | 
    
         
            -
            client sends a `HELLO` message, after which it immediately expects some answer
         
     | 
| 
       155 
     | 
    
         
            -
            from the broker (see above). After that, it just listens for messages (service
         
     | 
| 
       156 
     | 
    
         
            -
            requests) and prints them into the terminal.
         
     | 
| 
       157 
     | 
    
         
            -
             
     | 
| 
       158 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       159 
     | 
    
         
            -
            #!/usr/bin/env ruby
         
     | 
| 
       160 
     | 
    
         
            -
            require 'cztop'
         
     | 
| 
       161 
     | 
    
         
            -
             
     | 
| 
       162 
     | 
    
         
            -
            endpoint = ENV["BROKER_ADDRESS"]
         
     | 
| 
       163 
     | 
    
         
            -
            broker_cert = CZTop::Certificate.load ENV["BROKER_CERT"] # public only
         
     | 
| 
       164 
     | 
    
         
            -
            client_cert = CZTop::Certificate.load ENV["CLIENT_CERT"]
         
     | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
            @socket = CZTop::Socket::CLIENT.new
         
     | 
| 
       167 
     | 
    
         
            -
            @socket.CURVE_client!(client_cert, broker_cert)
         
     | 
| 
       168 
     | 
    
         
            -
            @socket.options.sndtimeo     = 2000#ms
         
     | 
| 
       169 
     | 
    
         
            -
             
     | 
| 
       170 
     | 
    
         
            -
            # heartbeating:
         
     | 
| 
       171 
     | 
    
         
            -
            # * send PING every 100ms
         
     | 
| 
       172 
     | 
    
         
            -
            # * close connection after 300ms of no life sign from broker
         
     | 
| 
       173 
     | 
    
         
            -
            # * tell broker to close connection after 500ms of no life sign from client
         
     | 
| 
       174 
     | 
    
         
            -
            @socket.options.heartbeat_ivl     = 100#ms
         
     | 
| 
       175 
     | 
    
         
            -
            @socket.options.heartbeat_timeout = 300#ms
         
     | 
| 
       176 
     | 
    
         
            -
            @socket.options.heartbeat_ttl     = 500#ms
         
     | 
| 
       177 
     | 
    
         
            -
             
     | 
| 
       178 
     | 
    
         
            -
            @socket.connect(endpoint)
         
     | 
| 
       179 
     | 
    
         
            -
            puts ">>> connected."
         
     | 
| 
       180 
     | 
    
         
            -
             
     | 
| 
       181 
     | 
    
         
            -
            # tell broker who we are
         
     | 
| 
       182 
     | 
    
         
            -
            @socket << "HELLO\t#{client_cert["driver_name"]}"
         
     | 
| 
       183 
     | 
    
         
            -
            puts ">>> sent HELLO."
         
     | 
| 
       184 
     | 
    
         
            -
            welcome = @socket.receive[0]
         
     | 
| 
       185 
     | 
    
         
            -
            puts ">>> got #{welcome}."
         
     | 
| 
       186 
     | 
    
         
            -
             
     | 
| 
       187 
     | 
    
         
            -
            poller = CZTop::Poller.new(@socket)
         
     | 
| 
       188 
     | 
    
         
            -
            while true
         
     | 
| 
       189 
     | 
    
         
            -
              socket = poller.wait
         
     | 
| 
       190 
     | 
    
         
            -
              message = socket.receive
         
     | 
| 
       191 
     | 
    
         
            -
              puts ">>> received message: #{message[0].inspect}"
         
     | 
| 
       192 
     | 
    
         
            -
            end
         
     | 
| 
       193 
     | 
    
         
            -
            ```
         
     | 
| 
       194 
     | 
    
         
            -
             
     | 
| 
       195 
     | 
    
         
            -
            ## How to run the example
         
     | 
| 
       196 
     | 
    
         
            -
             
     | 
| 
       197 
     | 
    
         
            -
            ### Generate broker's and drivers' keys
         
     | 
| 
       198 
     | 
    
         
            -
             
     | 
| 
       199 
     | 
    
         
            -
            Here's a simple script that'll create the broker's certificate and the taxi
         
     | 
| 
       200 
     | 
    
         
            -
            drivers' certificates. There are also public key only files so a minimum amount
         
     | 
| 
       201 
     | 
    
         
            -
            of information can be made available on one system, e.g. a taxi driver's system
         
     | 
| 
       202 
     | 
    
         
            -
            must not know the broker's secret key. Also, the broker doesn't necessarily
         
     | 
| 
       203 
     | 
    
         
            -
            need to know the clients' secret keys just to authenticate them.
         
     | 
| 
       204 
     | 
    
         
            -
             
     | 
| 
       205 
     | 
    
         
            -
            ```ruby
         
     | 
| 
       206 
     | 
    
         
            -
            #!/usr/bin/env ruby
         
     | 
| 
       207 
     | 
    
         
            -
            require 'cztop'
         
     | 
| 
       208 
     | 
    
         
            -
            require 'fileutils'
         
     | 
| 
       209 
     | 
    
         
            -
            FileUtils.cd(File.dirname(__FILE__))
         
     | 
| 
       210 
     | 
    
         
            -
            FileUtils.mkdir "public_keys"
         
     | 
| 
       211 
     | 
    
         
            -
            FileUtils.mkdir "public_keys/drivers"
         
     | 
| 
       212 
     | 
    
         
            -
            FileUtils.mkdir "secret_keys"
         
     | 
| 
       213 
     | 
    
         
            -
            FileUtils.mkdir "secret_keys/drivers"
         
     | 
| 
       214 
     | 
    
         
            -
            #FileUtils.mkdir "certs/drivers"
         
     | 
| 
       215 
     | 
    
         
            -
             
     | 
| 
       216 
     | 
    
         
            -
            DRIVERS = %w[ driver1 driver2 driver3 ]
         
     | 
| 
       217 
     | 
    
         
            -
             
     | 
| 
       218 
     | 
    
         
            -
            # broker certificate
         
     | 
| 
       219 
     | 
    
         
            -
            cert = CZTop::Certificate.new
         
     | 
| 
       220 
     | 
    
         
            -
            cert.save("secret_keys/broker")
         
     | 
| 
       221 
     | 
    
         
            -
            cert.save_public("public_keys/broker")
         
     | 
| 
       222 
     | 
    
         
            -
             
     | 
| 
       223 
     | 
    
         
            -
            # driver certificates
         
     | 
| 
       224 
     | 
    
         
            -
            DRIVERS.each do |driver_name|
         
     | 
| 
       225 
     | 
    
         
            -
              cert = CZTop::Certificate.new
         
     | 
| 
       226 
     | 
    
         
            -
              cert["driver_name"] = driver_name
         
     | 
| 
       227 
     | 
    
         
            -
              cert.save "secret_keys/drivers/#{driver_name}"
         
     | 
| 
       228 
     | 
    
         
            -
              cert.save_public "public_keys/drivers/#{driver_name}"
         
     | 
| 
       229 
     | 
    
         
            -
            end
         
     | 
| 
       230 
     | 
    
         
            -
             
     | 
| 
       231 
     | 
    
         
            -
            ```
         
     | 
| 
       232 
     | 
    
         
            -
            Run it as follows:
         
     | 
| 
       233 
     | 
    
         
            -
             
     | 
| 
       234 
     | 
    
         
            -
            ```
         
     | 
| 
       235 
     | 
    
         
            -
            ./generate_keys.rb
         
     | 
| 
       236 
     | 
    
         
            -
            ```
         
     | 
| 
       237 
     | 
    
         
            -
             
     | 
| 
       238 
     | 
    
         
            -
            ### Start broker
         
     | 
| 
       239 
     | 
    
         
            -
             
     | 
| 
       240 
     | 
    
         
            -
            Run this:
         
     | 
| 
       241 
     | 
    
         
            -
             
     | 
| 
       242 
     | 
    
         
            -
            ```
         
     | 
| 
       243 
     | 
    
         
            -
            ./start_broker.sh
         
     | 
| 
       244 
     | 
    
         
            -
            ```
         
     | 
| 
       245 
     | 
    
         
            -
             
     | 
| 
       246 
     | 
    
         
            -
            which will execute the following script:
         
     | 
| 
       247 
     | 
    
         
            -
             
     | 
| 
       248 
     | 
    
         
            -
            ```sh
         
     | 
| 
       249 
     | 
    
         
            -
            #!/bin/sh -x
         
     | 
| 
       250 
     | 
    
         
            -
            BROKER_ADDRESS=tcp://127.0.0.1:4455 BROKER_CERT=secret_keys/broker CLIENT_CERTS=public_keys/drivers ./broker.rb
         
     | 
| 
       251 
     | 
    
         
            -
            ```
         
     | 
| 
       252 
     | 
    
         
            -
             
     | 
| 
       253 
     | 
    
         
            -
            ### Start driver software instances
         
     | 
| 
       254 
     | 
    
         
            -
             
     | 
| 
       255 
     | 
    
         
            -
            Run this in another terminal:
         
     | 
| 
       256 
     | 
    
         
            -
             
     | 
| 
       257 
     | 
    
         
            -
            ```
         
     | 
| 
       258 
     | 
    
         
            -
            ./start_clients.sh
         
     | 
| 
       259 
     | 
    
         
            -
            ```
         
     | 
| 
       260 
     | 
    
         
            -
             
     | 
| 
       261 
     | 
    
         
            -
            which will execute the following script:
         
     | 
| 
       262 
     | 
    
         
            -
             
     | 
| 
       263 
     | 
    
         
            -
            ```sh
         
     | 
| 
       264 
     | 
    
         
            -
            #!/bin/sh -x
         
     | 
| 
       265 
     | 
    
         
            -
            export BROKER_ADDRESS=tcp://127.0.0.1:4455
         
     | 
| 
       266 
     | 
    
         
            -
            export BROKER_CERT=public_keys/broker
         
     | 
| 
       267 
     | 
    
         
            -
            CLIENT_CERT=secret_keys/drivers/driver1_secret ./client.rb &
         
     | 
| 
       268 
     | 
    
         
            -
            CLIENT_CERT=secret_keys/drivers/driver2_secret ./client.rb &
         
     | 
| 
       269 
     | 
    
         
            -
            CLIENT_CERT=secret_keys/drivers/driver3_secret ./client.rb &
         
     | 
| 
       270 
     | 
    
         
            -
            jobs
         
     | 
| 
       271 
     | 
    
         
            -
            jobs -p
         
     | 
| 
       272 
     | 
    
         
            -
            jobs -l
         
     | 
| 
       273 
     | 
    
         
            -
            trap 'kill $(jobs -p)' EXIT
         
     | 
| 
       274 
     | 
    
         
            -
            wait
         
     | 
| 
       275 
     | 
    
         
            -
            ```
         
     | 
| 
       276 
     | 
    
         
            -
             
     | 
| 
         @@ -1,97 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #!/usr/bin/env ruby
         
     | 
| 
       2 
     | 
    
         
            -
            require 'pry'
         
     | 
| 
       3 
     | 
    
         
            -
            require 'pathname'
         
     | 
| 
       4 
     | 
    
         
            -
            require 'cztop'
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
            endpoint = ENV["BROKER_ADDRESS"]
         
     | 
| 
       7 
     | 
    
         
            -
            broker_cert = CZTop::Certificate.load ENV["BROKER_CERT"] # secret+public
         
     | 
| 
       8 
     | 
    
         
            -
            client_certs = ENV["CLIENT_CERTS"] # /path/to/client_certs/
         
     | 
| 
       9 
     | 
    
         
            -
            drivers = Pathname.new(client_certs).children.map(&:basename).map(&:to_s)
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
            authenticator = CZTop::Authenticator.new
         
     | 
| 
       12 
     | 
    
         
            -
            authenticator.verbose!
         
     | 
| 
       13 
     | 
    
         
            -
            authenticator.curve(client_certs)
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
            # create and bind socket
         
     | 
| 
       16 
     | 
    
         
            -
            @socket = CZTop::Socket::SERVER.new
         
     | 
| 
       17 
     | 
    
         
            -
            @socket.CURVE_server!(broker_cert)
         
     | 
| 
       18 
     | 
    
         
            -
            #socket.options.sndtimeo = 0
         
     | 
| 
       19 
     | 
    
         
            -
            @socket.options.heartbeat_ivl     = 100#ms
         
     | 
| 
       20 
     | 
    
         
            -
            @socket.options.heartbeat_timeout = 300#ms
         
     | 
| 
       21 
     | 
    
         
            -
            @socket.bind(endpoint)
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
            puts ">>> Socket bound to #{endpoint.inspect}"
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
            # get and print socket events
         
     | 
| 
       26 
     | 
    
         
            -
            Thread.new do
         
     | 
| 
       27 
     | 
    
         
            -
              monitor = CZTop::Monitor.new(@socket)
         
     | 
| 
       28 
     | 
    
         
            -
              monitor.listen("ALL")
         
     | 
| 
       29 
     | 
    
         
            -
              monitor.start
         
     | 
| 
       30 
     | 
    
         
            -
              while msg = monitor.next
         
     | 
| 
       31 
     | 
    
         
            -
                puts ">>> Socket event: #{msg.inspect}"
         
     | 
| 
       32 
     | 
    
         
            -
              end
         
     | 
| 
       33 
     | 
    
         
            -
            end
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
            # receive messages from drivers
         
     | 
| 
       36 
     | 
    
         
            -
            @driver_map = {} # driver name => routing ID
         
     | 
| 
       37 
     | 
    
         
            -
            Thread.new do
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
              poller = CZTop::Poller.new(@socket)
         
     | 
| 
       40 
     | 
    
         
            -
              while true
         
     | 
| 
       41 
     | 
    
         
            -
                puts "waiting for socket to become readable ..."
         
     | 
| 
       42 
     | 
    
         
            -
                socket = poller.simple_wait
         
     | 
| 
       43 
     | 
    
         
            -
                puts "socket is readable"
         
     | 
| 
       44 
     | 
    
         
            -
                msg = socket.receive
         
     | 
| 
       45 
     | 
    
         
            -
                puts "got message"
         
     | 
| 
       46 
     | 
    
         
            -
                command, argument = msg[0].split("\t", 2)
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
                case command
         
     | 
| 
       49 
     | 
    
         
            -
                when "HELLO"
         
     | 
| 
       50 
     | 
    
         
            -
                  driver = argument
         
     | 
| 
       51 
     | 
    
         
            -
                  puts ">>> Driver #{driver.inspect} has connected."
         
     | 
| 
       52 
     | 
    
         
            -
                  welcome = @driver_map.key?(driver) ? "WELCOMEBACK" : "WELCOME"
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
                  # remember driver's assigned message routing ID
         
     | 
| 
       55 
     | 
    
         
            -
                  @driver_map[driver] = msg.routing_id
         
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
                  # send WELCOME or WELCOMEBACK
         
     | 
| 
       58 
     | 
    
         
            -
                  rep = CZTop::Message.new(welcome)
         
     | 
| 
       59 
     | 
    
         
            -
                  rep.routing_id = @driver_map[driver]
         
     | 
| 
       60 
     | 
    
         
            -
                  socket << rep
         
     | 
| 
       61 
     | 
    
         
            -
                  puts ">>> Sent #{welcome.inspect} to #{driver.inspect}"
         
     | 
| 
       62 
     | 
    
         
            -
                end
         
     | 
| 
       63 
     | 
    
         
            -
              end
         
     | 
| 
       64 
     | 
    
         
            -
            end
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
            def send_command(driver, command)
         
     | 
| 
       67 
     | 
    
         
            -
              if command.nil? || command.empty?
         
     | 
| 
       68 
     | 
    
         
            -
                puts "!!! No message given."
         
     | 
| 
       69 
     | 
    
         
            -
                return
         
     | 
| 
       70 
     | 
    
         
            -
              end
         
     | 
| 
       71 
     | 
    
         
            -
              if not @driver_map.key?(driver)
         
     | 
| 
       72 
     | 
    
         
            -
                puts "!!! Driver #{driver.inspect} has never connected."
         
     | 
| 
       73 
     | 
    
         
            -
                return
         
     | 
| 
       74 
     | 
    
         
            -
              end
         
     | 
| 
       75 
     | 
    
         
            -
              puts ">>> Sending message to #{driver.inspect} ..."
         
     | 
| 
       76 
     | 
    
         
            -
              msg = CZTop::Message.new(command)
         
     | 
| 
       77 
     | 
    
         
            -
              msg.routing_id = @driver_map[driver]
         
     | 
| 
       78 
     | 
    
         
            -
              @socket << msg
         
     | 
| 
       79 
     | 
    
         
            -
            rescue SocketError
         
     | 
| 
       80 
     | 
    
         
            -
              puts "!!! Driver #{driver.inspect} isn't connected anymore."
         
     | 
| 
       81 
     | 
    
         
            -
            end
         
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
            ##
         
     | 
| 
       84 
     | 
    
         
            -
            # REPL for user to play
         
     | 
| 
       85 
     | 
    
         
            -
            #
         
     | 
| 
       86 
     | 
    
         
            -
            puts <<MSG
         
     | 
| 
       87 
     | 
    
         
            -
            You can now send messages to the drivers yourself.
         
     | 
| 
       88 
     | 
    
         
            -
            The use the method #send_command, like this:
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
            pry> send_command("driver1", "PICKUP\t(8.541694,47.376887)")
         
     | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
       92 
     | 
    
         
            -
            This should show something like this in the client.rb terminal:
         
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
              03:17:01 driver1.1 | received message: "PICKUP\t(8.541694,47.376887)"
         
     | 
| 
       95 
     | 
    
         
            -
            MSG
         
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
            binding.pry
         
     | 
| 
         @@ -1,34 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #!/usr/bin/env ruby
         
     | 
| 
       2 
     | 
    
         
            -
            require 'cztop'
         
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
            endpoint = ENV["BROKER_ADDRESS"]
         
     | 
| 
       5 
     | 
    
         
            -
            broker_cert = CZTop::Certificate.load ENV["BROKER_CERT"] # public only
         
     | 
| 
       6 
     | 
    
         
            -
            client_cert = CZTop::Certificate.load ENV["CLIENT_CERT"]
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
            @socket = CZTop::Socket::CLIENT.new
         
     | 
| 
       9 
     | 
    
         
            -
            @socket.CURVE_client!(client_cert, broker_cert)
         
     | 
| 
       10 
     | 
    
         
            -
            @socket.options.sndtimeo     = 2000#ms
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
            # heartbeating:
         
     | 
| 
       13 
     | 
    
         
            -
            # * send PING every 100ms
         
     | 
| 
       14 
     | 
    
         
            -
            # * close connection after 300ms of no life sign from broker
         
     | 
| 
       15 
     | 
    
         
            -
            # * tell broker to close connection after 500ms of no life sign from client
         
     | 
| 
       16 
     | 
    
         
            -
            @socket.options.heartbeat_ivl     = 100#ms
         
     | 
| 
       17 
     | 
    
         
            -
            @socket.options.heartbeat_timeout = 300#ms
         
     | 
| 
       18 
     | 
    
         
            -
            @socket.options.heartbeat_ttl     = 500#ms
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
            @socket.connect(endpoint)
         
     | 
| 
       21 
     | 
    
         
            -
            puts ">>> connected."
         
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
            # tell broker who we are
         
     | 
| 
       24 
     | 
    
         
            -
            @socket << "HELLO\t#{client_cert["driver_name"]}"
         
     | 
| 
       25 
     | 
    
         
            -
            puts ">>> sent HELLO."
         
     | 
| 
       26 
     | 
    
         
            -
            welcome = @socket.receive[0]
         
     | 
| 
       27 
     | 
    
         
            -
            puts ">>> got #{welcome}."
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
            poller = CZTop::Poller.new(@socket)
         
     | 
| 
       30 
     | 
    
         
            -
            while true
         
     | 
| 
       31 
     | 
    
         
            -
              socket = poller.simple_wait
         
     | 
| 
       32 
     | 
    
         
            -
              message = socket.receive
         
     | 
| 
       33 
     | 
    
         
            -
              puts ">>> received message: #{message[0].inspect}"
         
     | 
| 
       34 
     | 
    
         
            -
            end
         
     | 
| 
         @@ -1,24 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #!/usr/bin/env ruby
         
     | 
| 
       2 
     | 
    
         
            -
            require 'cztop'
         
     | 
| 
       3 
     | 
    
         
            -
            require 'fileutils'
         
     | 
| 
       4 
     | 
    
         
            -
            FileUtils.cd(File.dirname(__FILE__))
         
     | 
| 
       5 
     | 
    
         
            -
            FileUtils.mkdir "public_keys"
         
     | 
| 
       6 
     | 
    
         
            -
            FileUtils.mkdir "public_keys/drivers"
         
     | 
| 
       7 
     | 
    
         
            -
            FileUtils.mkdir "secret_keys"
         
     | 
| 
       8 
     | 
    
         
            -
            FileUtils.mkdir "secret_keys/drivers"
         
     | 
| 
       9 
     | 
    
         
            -
            #FileUtils.mkdir "certs/drivers"
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
            DRIVERS = %w[ driver1 driver2 driver3 ]
         
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
            # broker certificate
         
     | 
| 
       14 
     | 
    
         
            -
            cert = CZTop::Certificate.new
         
     | 
| 
       15 
     | 
    
         
            -
            cert.save("secret_keys/broker")
         
     | 
| 
       16 
     | 
    
         
            -
            cert.save_public("public_keys/broker")
         
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
            # driver certificates
         
     | 
| 
       19 
     | 
    
         
            -
            DRIVERS.each do |driver_name|
         
     | 
| 
       20 
     | 
    
         
            -
              cert = CZTop::Certificate.new
         
     | 
| 
       21 
     | 
    
         
            -
              cert["driver_name"] = driver_name
         
     | 
| 
       22 
     | 
    
         
            -
              cert.save "secret_keys/drivers/#{driver_name}"
         
     | 
| 
       23 
     | 
    
         
            -
              cert.save_public "public_keys/drivers/#{driver_name}"
         
     | 
| 
       24 
     | 
    
         
            -
            end
         
     | 
| 
         @@ -1,11 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #!/bin/sh -x
         
     | 
| 
       2 
     | 
    
         
            -
            export BROKER_ADDRESS=tcp://127.0.0.1:4455
         
     | 
| 
       3 
     | 
    
         
            -
            export BROKER_CERT=public_keys/broker
         
     | 
| 
       4 
     | 
    
         
            -
            CLIENT_CERT=secret_keys/drivers/driver1_secret ./client.rb &
         
     | 
| 
       5 
     | 
    
         
            -
            CLIENT_CERT=secret_keys/drivers/driver2_secret ./client.rb &
         
     | 
| 
       6 
     | 
    
         
            -
            CLIENT_CERT=secret_keys/drivers/driver3_secret ./client.rb &
         
     | 
| 
       7 
     | 
    
         
            -
            jobs
         
     | 
| 
       8 
     | 
    
         
            -
            jobs -p
         
     | 
| 
       9 
     | 
    
         
            -
            jobs -l
         
     | 
| 
       10 
     | 
    
         
            -
            trap 'kill $(jobs -p)' EXIT
         
     | 
| 
       11 
     | 
    
         
            -
            wait
         
     | 
| 
         @@ -1,24 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #!/usr/bin/env ruby
         
     | 
| 
       2 
     | 
    
         
            -
            #
         
     | 
| 
       3 
     | 
    
         
            -
            # Weather update server, based on ZMQ's zguide.
         
     | 
| 
       4 
     | 
    
         
            -
            # Binds PUB socket to ipc:///tmp/weather_pubsub_example
         
     | 
| 
       5 
     | 
    
         
            -
            # Publishes random weather updates
         
     | 
| 
       6 
     | 
    
         
            -
            #
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
            require 'cztop'
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
            # create and bind socket
         
     | 
| 
       11 
     | 
    
         
            -
            socket = CZTop::Socket::PUB.new("ipc:///tmp/weather_pubsub_example")
         
     | 
| 
       12 
     | 
    
         
            -
            puts "<<< Socket bound to #{socket.last_endpoint.inspect}"
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
            while true
         
     | 
| 
       15 
     | 
    
         
            -
            	# Generate values for zipcodes
         
     | 
| 
       16 
     | 
    
         
            -
            	zipcode = rand(100000)
         
     | 
| 
       17 
     | 
    
         
            -
            	temperature = rand(215) - 80
         
     | 
| 
       18 
     | 
    
         
            -
            	relhumidity = rand(50) + 10
         
     | 
| 
       19 
     | 
    
         
            -
            	
         
     | 
| 
       20 
     | 
    
         
            -
            	update = "%05d %d %d" % [zipcode, temperature, relhumidity]
         
     | 
| 
       21 
     | 
    
         
            -
            	puts update
         
     | 
| 
       22 
     | 
    
         
            -
            	
         
     | 
| 
       23 
     | 
    
         
            -
            	socket << update
         
     | 
| 
       24 
     | 
    
         
            -
            end
         
     | 
| 
         @@ -1,33 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #!/usr/bin/env ruby
         
     | 
| 
       2 
     | 
    
         
            -
            #
         
     | 
| 
       3 
     | 
    
         
            -
            # Weather update client, based on that from ZMQ's zguide.
         
     | 
| 
       4 
     | 
    
         
            -
            # Connects SUB socket to ipc:///tmp/weather_pubsub_example
         
     | 
| 
       5 
     | 
    
         
            -
            # Collects weather updates and finds avg temp in zipcode
         
     | 
| 
       6 
     | 
    
         
            -
            #
         
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
            require 'cztop'
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
            COUNT = 100
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
            # Create socket, connect to publisher.
         
     | 
| 
       13 
     | 
    
         
            -
            socket = CZTop::Socket::SUB.new("ipc:///tmp/weather_pubsub_example")
         
     | 
| 
       14 
     | 
    
         
            -
            puts ">>> Socket Connected"
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
            # Subscribe to zipcode.  Default: Chicago - 60606
         
     | 
| 
       17 
     | 
    
         
            -
            filter = ARGV.size > 0 ? ARGV[0] : "60606"
         
     | 
| 
       18 
     | 
    
         
            -
            socket.subscribe(filter)
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
            # gather & process COUNT updates.
         
     | 
| 
       21 
     | 
    
         
            -
            print "Gathering #{COUNT} samples."
         
     | 
| 
       22 
     | 
    
         
            -
            total_temp = 0
         
     | 
| 
       23 
     | 
    
         
            -
            1.upto(COUNT) do |update_nbr|
         
     | 
| 
       24 
     | 
    
         
            -
            	msg = socket.receive
         
     | 
| 
       25 
     | 
    
         
            -
            	
         
     | 
| 
       26 
     | 
    
         
            -
            	zipcode, temperature, relhumidity = msg[0].split.map(&:to_i)
         
     | 
| 
       27 
     | 
    
         
            -
            	total_temp += temperature
         
     | 
| 
       28 
     | 
    
         
            -
            	# just to show that we're doing something...
         
     | 
| 
       29 
     | 
    
         
            -
            	print "." if update_nbr % 5 == 0
         
     | 
| 
       30 
     | 
    
         
            -
            end
         
     | 
| 
       31 
     | 
    
         
            -
            print "\n"
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
            puts "Average temperatuer for zipcode #{filter} was #{total_temp / COUNT}F."
         
     | 
    
        data/perf/README.md
    DELETED
    
    | 
         @@ -1,80 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # Performance Measurement
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            This directory contains simple performance measurement utilities:
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            - `inproc_lat.rb` measures the latency of the inproc transport
         
     | 
| 
       6 
     | 
    
         
            -
            - `inproc_thru.rb` measures the throughput of the inproc transport
         
     | 
| 
       7 
     | 
    
         
            -
            - `local_lat.rb` and `remote_lat.rb` measure the latency of other transports
         
     | 
| 
       8 
     | 
    
         
            -
            - `local_thru.rb` and `remote_thru.rb` measure the throughput of other transports (TODO)
         
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
            ## Example Output
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
            On my laptop, it currently looks something like this:
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
            ### Latency
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
            over inproc, using 10k roundtrips of a repeatedly allocated 1kb message:
         
     | 
| 
       17 
     | 
    
         
            -
            ```
         
     | 
| 
       18 
     | 
    
         
            -
            $ bundle exec ./inproc_lat_reqrep.rb 1_000 10_000
         
     | 
| 
       19 
     | 
    
         
            -
            message size: 1000 [B]
         
     | 
| 
       20 
     | 
    
         
            -
            roundtrip count: 10000
         
     | 
| 
       21 
     | 
    
         
            -
            elapsed time: 0.469 [s]
         
     | 
| 
       22 
     | 
    
         
            -
            average latency: 23.439 [us]<Paste>
         
     | 
| 
       23 
     | 
    
         
            -
            ```
         
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
            over IPC, using 10k roundtrips of a repeatedly allocated 1kb message:
         
     | 
| 
       26 
     | 
    
         
            -
            ```
         
     | 
| 
       27 
     | 
    
         
            -
            $ bundle exec ./local_lat.rb ipc:///tmp/cztop-perf 1000 1000 & ./remote_lat.rb ipc:///tmp/cztop-perf 1000 1000
         
     | 
| 
       28 
     | 
    
         
            -
            [3] 58043
         
     | 
| 
       29 
     | 
    
         
            -
            message size: 1000 [B]
         
     | 
| 
       30 
     | 
    
         
            -
            roundtrip count: 1000
         
     | 
| 
       31 
     | 
    
         
            -
            elapsed time: 0.091 [s]
         
     | 
| 
       32 
     | 
    
         
            -
            average latency: 45.482 [us]
         
     | 
| 
       33 
     | 
    
         
            -
            [3]    58043 done       ./local_lat.rb ipc:///tmp/cztop-perf 1000 1000
         
     | 
| 
       34 
     | 
    
         
            -
            ```
         
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
            over local TCP/IP stack, using 10k roundtrips of a repeatedly allocated
         
     | 
| 
       37 
     | 
    
         
            -
            1kb message:
         
     | 
| 
       38 
     | 
    
         
            -
            ```
         
     | 
| 
       39 
     | 
    
         
            -
            $ bundle exec ./local_lat.rb tcp://127.0.0.1:55667 1000 1000 & ./remote_lat.rb tcp://127.0.0.1:55667 1000 1000
         
     | 
| 
       40 
     | 
    
         
            -
            [3] 58064
         
     | 
| 
       41 
     | 
    
         
            -
            message size: 1000 [B]
         
     | 
| 
       42 
     | 
    
         
            -
            roundtrip count: 1000
         
     | 
| 
       43 
     | 
    
         
            -
            elapsed time: 0.123 [s]
         
     | 
| 
       44 
     | 
    
         
            -
            average latency: 61.434 [us]
         
     | 
| 
       45 
     | 
    
         
            -
            [3]    58064 done       ./local_lat.rb tcp://127.0.0.1:55667 1000 1000
         
     | 
| 
       46 
     | 
    
         
            -
            ```
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
            ### Throughput
         
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
            over inproc, with message sizes from 100 bytes to 100kb, 10,000 each:
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
            ```
         
     | 
| 
       53 
     | 
    
         
            -
            $ bundle exec ./inproc_thru.rb 100 10_000
         
     | 
| 
       54 
     | 
    
         
            -
            message size: 100 [B]
         
     | 
| 
       55 
     | 
    
         
            -
            message count: 10000
         
     | 
| 
       56 
     | 
    
         
            -
            elapsed time: 0.270 [s]
         
     | 
| 
       57 
     | 
    
         
            -
            mean throughput: 37093 [msg/s]
         
     | 
| 
       58 
     | 
    
         
            -
            mean throughput: 29.674 [Mb/s]
         
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
            $ bundle exec ./inproc_thru.rb 1_000 10_000
         
     | 
| 
       61 
     | 
    
         
            -
            message size: 1000 [B]
         
     | 
| 
       62 
     | 
    
         
            -
            message count: 10000
         
     | 
| 
       63 
     | 
    
         
            -
            elapsed time: 0.260 [s]
         
     | 
| 
       64 
     | 
    
         
            -
            mean throughput: 38498 [msg/s]
         
     | 
| 
       65 
     | 
    
         
            -
            mean throughput: 307.987 [Mb/s]
         
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
            $ bundle exec ./inproc_thru.rb 10_000 10_000
         
     | 
| 
       68 
     | 
    
         
            -
            message size: 10000 [B]
         
     | 
| 
       69 
     | 
    
         
            -
            message count: 10000
         
     | 
| 
       70 
     | 
    
         
            -
            elapsed time: 0.317 [s]
         
     | 
| 
       71 
     | 
    
         
            -
            mean throughput: 31501 [msg/s]
         
     | 
| 
       72 
     | 
    
         
            -
            mean throughput: 2520.102 [Mb/s]
         
     | 
| 
       73 
     | 
    
         
            -
             
     | 
| 
       74 
     | 
    
         
            -
            $ bundle exec ./inproc_thru.rb 100_000 10_000
         
     | 
| 
       75 
     | 
    
         
            -
            message size: 100000 [B]
         
     | 
| 
       76 
     | 
    
         
            -
            message count: 10000
         
     | 
| 
       77 
     | 
    
         
            -
            elapsed time: 0.906 [s]
         
     | 
| 
       78 
     | 
    
         
            -
            mean throughput: 11034 [msg/s]
         
     | 
| 
       79 
     | 
    
         
            -
            mean throughput: 8827.440 [Mb/s]
         
     | 
| 
       80 
     | 
    
         
            -
            ```
         
     | 
    
        data/perf/inproc_lat.rb
    DELETED
    
    | 
         @@ -1,49 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #! /usr/bin/env ruby
         
     | 
| 
       2 
     | 
    
         
            -
            require "cztop"
         
     | 
| 
       3 
     | 
    
         
            -
            require "benchmark"
         
     | 
| 
       4 
     | 
    
         
            -
            #require "ruby-prof"
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
            if ARGV.size != 2
         
     | 
| 
       7 
     | 
    
         
            -
              abort <<MSG
         
     | 
| 
       8 
     | 
    
         
            -
            Usage: #{$0} <message-size> <roundtrip-count>
         
     | 
| 
       9 
     | 
    
         
            -
            MSG
         
     | 
| 
       10 
     | 
    
         
            -
            end
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
            MSG_SIZE = Integer(ARGV[0]) # bytes
         
     | 
| 
       13 
     | 
    
         
            -
            ROUNDTRIP_COUNT = Integer(ARGV[1]) # round trips
         
     | 
| 
       14 
     | 
    
         
            -
            MSG = "X" * MSG_SIZE
         
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
            Thread.new do
         
     | 
| 
       17 
     | 
    
         
            -
              s = CZTop::Socket::PAIR.new("@inproc://perf")
         
     | 
| 
       18 
     | 
    
         
            -
              s.signal
         
     | 
| 
       19 
     | 
    
         
            -
              ROUNDTRIP_COUNT.times do
         
     | 
| 
       20 
     | 
    
         
            -
                msg = s.receive
         
     | 
| 
       21 
     | 
    
         
            -
                raise "wrong message size" if msg.content_size != MSG_SIZE
         
     | 
| 
       22 
     | 
    
         
            -
                s << msg
         
     | 
| 
       23 
     | 
    
         
            -
              end
         
     | 
| 
       24 
     | 
    
         
            -
            end
         
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
            s = CZTop::Socket::PAIR.new(">inproc://perf")
         
     | 
| 
       27 
     | 
    
         
            -
            s.wait
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
            #RubyProf.start
         
     | 
| 
       30 
     | 
    
         
            -
            tms = Benchmark.measure do
         
     | 
| 
       31 
     | 
    
         
            -
              ROUNDTRIP_COUNT.times do
         
     | 
| 
       32 
     | 
    
         
            -
                s << MSG
         
     | 
| 
       33 
     | 
    
         
            -
                msg = s.receive
         
     | 
| 
       34 
     | 
    
         
            -
                raise "wrong message size" if msg.content_size != MSG_SIZE
         
     | 
| 
       35 
     | 
    
         
            -
              end
         
     | 
| 
       36 
     | 
    
         
            -
            end
         
     | 
| 
       37 
     | 
    
         
            -
            #rubyprof_result = RubyProf.stop
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
            elapsed = tms.real
         
     | 
| 
       40 
     | 
    
         
            -
            latency = elapsed / (ROUNDTRIP_COUNT * 2) * 1_000_000
         
     | 
| 
       41 
     | 
    
         
            -
            puts "message size: #{MSG_SIZE} [B]"
         
     | 
| 
       42 
     | 
    
         
            -
            puts "roundtrip count: #{ROUNDTRIP_COUNT}"
         
     | 
| 
       43 
     | 
    
         
            -
            puts "elapsed time: %.3f [s]" % elapsed
         
     | 
| 
       44 
     | 
    
         
            -
            puts "average latency: %.3f [us]" % latency
         
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
            # print a flat profile to text
         
     | 
| 
       47 
     | 
    
         
            -
            #printer = RubyProf::FlatPrinter.new(rubyprof_result)
         
     | 
| 
       48 
     | 
    
         
            -
            #printer.print(STDOUT)
         
     | 
| 
       49 
     | 
    
         
            -
             
     | 
    
        data/perf/inproc_thru.rb
    DELETED
    
    | 
         @@ -1,42 +0,0 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #! /usr/bin/env ruby
         
     | 
| 
       2 
     | 
    
         
            -
            require "cztop"
         
     | 
| 
       3 
     | 
    
         
            -
            require "benchmark"
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
            if ARGV.size != 2
         
     | 
| 
       6 
     | 
    
         
            -
              abort <<MSG
         
     | 
| 
       7 
     | 
    
         
            -
            Usage: #{$0} <message-size> <message-count>
         
     | 
| 
       8 
     | 
    
         
            -
            MSG
         
     | 
| 
       9 
     | 
    
         
            -
            end
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
            MSG_SIZE = Integer(ARGV[0]) # bytes
         
     | 
| 
       12 
     | 
    
         
            -
            MSG_COUNT = Integer(ARGV[1]) # number of messages
         
     | 
| 
       13 
     | 
    
         
            -
            MSG = "X" * MSG_SIZE
         
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
            Thread.new do
         
     | 
| 
       16 
     | 
    
         
            -
              s = CZTop::Socket::PAIR.new("@inproc://perf")
         
     | 
| 
       17 
     | 
    
         
            -
              s.signal
         
     | 
| 
       18 
     | 
    
         
            -
              MSG_COUNT.times do
         
     | 
| 
       19 
     | 
    
         
            -
                msg = s.receive
         
     | 
| 
       20 
     | 
    
         
            -
                raise "wrong message size" if msg.content_size != MSG_SIZE
         
     | 
| 
       21 
     | 
    
         
            -
              end
         
     | 
| 
       22 
     | 
    
         
            -
            end
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
            s = CZTop::Socket::PAIR.new(">inproc://perf")
         
     | 
| 
       25 
     | 
    
         
            -
            s.wait
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
            tms = Benchmark.measure do
         
     | 
| 
       28 
     | 
    
         
            -
              MSG_COUNT.times do
         
     | 
| 
       29 
     | 
    
         
            -
                s << MSG
         
     | 
| 
       30 
     | 
    
         
            -
              end
         
     | 
| 
       31 
     | 
    
         
            -
            end
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
            elapsed = tms.real
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
            throughput = MSG_COUNT / elapsed
         
     | 
| 
       36 
     | 
    
         
            -
            megabits = (throughput * MSG_SIZE * 8) / 1_000_000
         
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
            puts "message size: #{MSG_SIZE} [B]"
         
     | 
| 
       39 
     | 
    
         
            -
            puts "message count: #{MSG_COUNT}"
         
     | 
| 
       40 
     | 
    
         
            -
            puts "elapsed time: %.3f [s]" % elapsed
         
     | 
| 
       41 
     | 
    
         
            -
            puts "mean throughput: %d [msg/s]" % throughput
         
     | 
| 
       42 
     | 
    
         
            -
            puts "mean throughput: %.3f [Mb/s]" % megabits
         
     |