/NanoStrand

Smalltalk bindings for nanomsg

Primary LanguageSmalltalkMIT LicenseMIT

NanoStrand

Smalltalk bindings for nanomsg.

##Overview nanomsg is a simple, fast socket abstraction library that supports many communication patterns ("scalability protocols").

NanoStrand is a gate to the nanomsg world for Smalltalk users. Since there are many language-bindings for nanomsg, integrations with other network programs would be much simpler via NanoStrand.

NanoStrand is composed of two-parts:

  • A thin FFI wrapper of the nanomsg API (NanoStrand-FFI)
  • More "objectified" socket classes (NanoStrand-Core)

Currently FFI part is based on NativeBoost, so the main target is Pharo Smalltalk. But the FFI part will be pluggable for supporting other Smalltalk dialects (Squeak, Cuis, VisualWorks, etc).

For MCZ packages, visit SmalltalkHub NanoStrand site.

##Installation

  • Download and compile nanomsg.

    Please see the instruction in nanomsg site. You'll need 32-bit option (CFLAGS=-m32), if you use 32-bit Cog VM.

  • Put the nanomsg shared library (so, dll, or dylib) to the VM directory.

  • Load NanoStrand to Pharo.

Gofer new
      url: 'http://smalltalkhub.com/mc/MasashiUmezawa/NanoStrand/main';
      package: 'ConfigurationOfNanoStrand';
      load.
(Smalltalk at: #ConfigurationOfNanoStrand) load

##Examples

###Simple PULL / PUSH on one node

[[
"Setup PULL socket"
sock1 := NnPullSocket withBind: 'tcp://*:5575'.
sock1 onReceiveReady: [:sock | Transcript cr; show: '#PULL: ', sock receive asString].

"Setup PUSH socket"
sock2 := NnPushSocket withConnect: 'tcp://127.0.0.1:5575'.
sock2 onSendReady: [:sock | sock send: '#PUSH: ', Time now asString].

"Start a Poller for multiplexing"
poller := NnPoller startWithSockets: {sock1. sock2}.

1 seconds wait. "The process ends after a second"

] ensure: [
poller stopAndCloseSockets.
]] fork.

Let's try changing the source to accumulate the result to an OrderedCollection:

"Setup PULL socket"
ord := OrderedCollection new.
sock1 := NnPullSocket withBind: 'tcp://*:5575'.
sock1 onReceiveReady: [:sock | ord add: (sock receive asString)].

After running the program, we can see how many messages were processed.

"print it"
ord size. "=> 22852"

22852 messages per second on my MBA! It is pretty fast.

###PULL + PUB server connected with PUSH / SUB multi clients

####Server - PULL + PUB This Smalltalk server pulls the messages from clients and pushes 'rem' events.

[[
received := OrderedCollection new. "A message box"

"Setup PULL socket"
sock1 := NnPullSocket withBind: 'tcp://127.0.0.1:5585'.
sock1 onReceiveReady: [:sock | | rec |
	rec := (sock receiveFor: 200 timeoutDo: ['']) asString.
	rec ifNotEmpty: [
		received add: rec. "Stock the received message"
		Transcript cr; show: 'Received:', rec, ':', Time now asString].
].

"Setup PUB socket"
sock2 := NnPubSocket withBind: 'tcp://127.0.0.1:5586'.
sock2 onSendReady: [:sock | |rem |
	rem := received size rem: 10. "Compute the rem:10 of the messages."
	
	"If rem is 0 or 5, publish the events."
	rem = 0 ifTrue: [sock send: 'Evt:Rem0:', Time now asString].
	rem = 5 ifTrue: [sock send: 'Evt:Rem5:', Time now asString].
].

poller := NnPoller new.
poller startWithSockets: {sock1. sock2}.

30 seconds wait. "The demo server ends after 30 seconds. So, be quick!"

] ensure: [
poller stopAndCloseSockets.
]] fork.

For clients, we use nanocat. An official command line client of nanomsg (in C).

####Client 1 - PUSH Pushes "HelloWorld" messages periodically.

$ nanocat --push --connect tcp://127.0.0.1:5585 --data HelloWorld -i 1

####Client 2 - SUB Subscribes to all events.

$ nanocat --sub --connect tcp://127.0.0.1:5586 -A

####Client 3 - SUB Subscribes to 'Event:Rem0' only.

$ nanocat --sub --connect tcp://127.0.0.1:5586 --subscribe Evt:Rem0 -A

Now you can see that after Client 1's messages are stocked on server, Rem0 & Rem5 events will be delivered to Clients 2, and Rem0 events will be delivered to Client 3.