1   Introduction

I've been experimenting with the implementation of microservices using ZeroMQ. What follows is a few notes on what I've been able to do.

I'll give examples written in both Lua and Python. The use of Lua is a bit interesting because Lua is especially useful and convenient for use as an embedded language.

Note that this code originated from the example code in the zguide - https://zguide.zeromq.org/. You can clone the zguide along with example code in multiple languages from https://github.com/imatix/zguide.git.

For similar examples in Node.js, see http://www.reifywork.com/zeromq-python-nodejs.html.

2   A simple first step - Local machine

Here is a simple server in Python - hwserver.py:

#!/usr/bin/env python

"""
synopsis:
    Hello World server in Python
    Binds REP socket to tcp://*:5555
    Expects b"Hello" from client, replies with b"World"
"""

# import time
import zmq


def receive_requests():
    """Receive the requests."""
    context = zmq.Context()
    socket = context.socket(zmq.REP)
    socket.bind("tcp://*:5555")
    # socket.bind("tcp://10.0.1.2:5555")
    count = -1
    while True:
        count += 1
        #  Wait for next request from client
        message = socket.recv()
        print(f"Received request: {message}")
        #  Do some 'work'
        # time.sleep(1)
        #  Send reply back to client
        socket.send_string(f"World {count}")


def main():
    """Main function"""
    receive_requests()


if __name__ == "__main__":
    main()

And, a very similar server written in Lua - hwserver.lua:

#!/usr/bin/env lua5.3

--  Hello World server
--  Binds REP socket to tcp://*:5555
--  Expects "Hello" from client, replies with "World"
--
--  Author: Robert G. Jakabosky <bobby@sharedrealm.com>
--
local zmq = require"zmq"
require"zhelpers"

local context = zmq.init(1)

--  Socket to talk to clients
local socket = context:socket(zmq.REP)
socket:bind("tcp://*:5555")

while true do
    --  Wait for next request from client
    local request = socket:recv()
    print("Received Hello [" .. request .. "]")

    --  Do some 'work'
                -- s_sleep(1000)

    --  Send reply back to client
    socket:send("World")
end
--  We never get here but if we did, this would be how we end
socket:close()
context:term()

And, here is a simple client written in Python:

#!/usr/bin/env python

"""
synopsis:
    Hello World client in Python
    Connects REQ socket to tcp://localhost:5555
    Sends "Hello" to server, expects "World" back
"""

import sys
import zmq


def send_requests(count):
    """Send the requests."""
    context = zmq.Context()
    #  Socket to talk to server
    print("Connecting to hello world server...")
    socket = context.socket(zmq.REQ)
    socket.connect("tcp://localhost:5555")
    for request in range(count):
        print(f"Sending request {request} ...")
        socket.send_string(f"Hello {request}")
        #  Get the reply.
        message = socket.recv()
        print(f"Received reply {request} [ {message} ]")


def main():
    """Main function"""
    args = sys.argv[1:]
    count = 10
    if len(args) == 1:
        count = int(args[0])
    send_requests(count)


if __name__ == "__main__":
    main()

Next, a very similar client written in Lua:

#!/usr/bin/env lua
--
--  Hello World client
--  Connects REQ socket to tcp://localhost:5555
--  Sends "Hello" to server, expects "World" back
--
--  Author: Robert G. Jakabosky <bobby@sharedrealm.com>
--
local zmq = require("zmq")
local fmt = string.format

local context = zmq.init(1)
local count = arg[1] or 10

--  Socket to talk to server
print("Connecting to hello world server...")
local socket = context:socket(zmq.REQ)
socket:connect("tcp://localhost:5555")

for n = 1, count do
  print("Sending Hello " .. n .. " ...")
  socket:send(fmt("Hello %s", n))

  local reply = socket:recv()
  print("Received World " .. n .. " [" .. reply .. "]")
end
socket:close()
context:term()

3   A next, not quite so simple step - a remote machine

In order to use ZeroMQ to make requests to and receive responses from a remote machine, we will need to create an SSH tunnel. It's easy, but it's also a bit non-obvious. Here is a bash shell script and the commands that we'll use:

#!/usr/bin/bash
ssh -f ec2-user@reifywork.com -L 5555:localhost:5555 -N
ssh -f dkuhlman@magpie -L 5556:localhost:5556 -N

Notes:

  • You will need to modify this script to reflect your access to your remote machine.
  • The above bash script actually creates two (2) SSH tunnels. The first is to a remote machine at reifywork.com out on the WAN (wide area network, i.e. the big Internet) and the second is to the machine magpie on my LAN (local area network).
  • In order to use the first tunnel, to reifywork.com, we'll use port 5555. And for the second, to magpie, we'll use port 5556.
  • reifywork.com will respond by using port 5555. And, magpie will respond through port 5556.
  • So, in this example, on the machine addressable as reifywork.com I'll implement and run a ZeroMQ server app that receives requests and sends responses through port 5555; and on the machine magpie on my LAN I'll implement and run a ZeroMQ server app that receives requests and sends responses through port 5556.
  • The above script starts two processes. Use htop or your own process monitor to verify that.
  • Because it creates processes, you will need to re-run that script anytime those processes are killed and you need them again. That happens, for example, when you shut down your machine.
  • For this to work, you will need access (without a password, I believe) in both directions. You can use ssh-keygen to generate authentication keys for ssh. You can do a Web search for how-to information on how to generate and install the authentication key on the remote machine.

Published

Category

network

Tags

Contact