I don't use this anymore, and don't plan on maintaining it. Please use at your own risk.
Nanomsg FFI bindings for PicoLisp.
The following protocols are supported:
- PicoLisp 64-bit
v17.12+
- Tested up to PicoLisp
v21
, see test runs - Git
- UNIX/Linux development/build tools (gcc, make/gmake/cmake, etc..)
To learn more about PicoLisp and this Nanomsg library, please read the EXPLAIN.md document.
This binding relies on the Official Nanomsg C Library, compiled as a shared library.
- Type
make
to pull and compile the Official Nanomsg C Library. - Include
nanomsg.l
in your project - Try the example below
Once compiled, the shared library is symlinked as:
.lib/libnanomsg.so -> .modules/nanomsg/HEAD/libnanomsg.so
The nanomsg.l
file searches for .lib/libnanomsg.so
, relative to its current directory.
To keep everything updated, type:
git pull && make clean && make
Only the following functions are considered public
:
protocol-bind
: bind aREP, PUB, BUS, PAIR, PULL, or SURVEYOR
socket (inproc, ipc, tcp)protocol-connect
: connect to aREQ, SUB, BUS, PAIR, PUSH, RESPONDENT
socket (inproc, ipc, tcp)end-sock
: shutdown and close a socketmsg-recv
: receive a message (blocking/non-blocking)msg-send
: send a message (blocking/non-blocking)subscribe
: subscribe to aPUB/SUB
topicunsubscribe
: unsubscribe from aPUB/SUB
topic
Note: These functions are not namespace local symbols, which means they would redefine symbols with the same name in the
'pico
namespace.
When an error occurs, 'InternalError
is thrown, along with the error (error type in car
, message in cdr
). The error will also be returned by the (catch)
expression. Ensure your (catch)
ends with NIL
.
pil +
(load "nanomsg.l")
(let Error
(catch 'InternalError
(protocol-bind "REP" "tcpz://127.0.0.1:5560" "AF_SP_RAW")
(prinl "you shouldn't see this") NIL)
(when Error (println @)) )
-> (NanomsgError . "Protocol not supported")
pil +
(load "nanomsg.l")
(unless (fork)
(let Sockpair
(protocol-bind "REP" "tcp://127.0.0.1:5560")
(prinl (msg-recv (car Sockpair)))
(msg-send (car Sockpair) "Yep I can see it!" T) # non-blocking
(end-sock Sockpair) )
(bye) )
# => Can you see this?
pil +
(load "nanomsg.l")
(unless (fork)
(let Sockpair
(protocol-connect "REQ" "tcp://127.0.0.1:5560")
(msg-send (car Sockpair) "Can you see this?")
(prinl (msg-recv (car Sockpair)))
(end-sock Sockpair) )
(bye) )
# => Yep I can see it!
pil +
(load "nanomsg.l")
(unless (fork)
(let Sockpair
(protocol-connect "SUB" "tcp://127.0.0.1:5560")
(subscribe (car Sockpair) "test")
(while T (prinl "RECEIVED: " (msg-recv (car Sockpair))) (wait 1000 (unsubscribe 0 "test")))
(end-sock Sockpair) )
(bye) )
# => RECEIVED: test Hello World!
pil +
(load "nanomsg.l")
(let Sockpair
(protocol-bind "PUB" "tcp://127.0.0.1:5560")
(while T (msg-send (car Sockpair) "test Hello World!"))
(end-sock Sockpair) )
pil +
(load "nanomsg.l")
(unless (fork)
(let Sockpair
(protocol-connect "BUS" "tcp://127.0.0.1:5560")
(prinl (msg-recv (car Sockpair)))
(end-sock Sockpair) )
(bye) )
# => Hello World!
pil +
(load "nanomsg.l")
(unless (fork)
(let Sockpair
(protocol-bind "BUS" "tcp://127.0.0.1:5560")
(msg-send (car Sockpair) "Hello World!")
(end-sock Sockpair) )
(bye) )
pil +
(load "nanomsg.l")
(unless (fork)
(let Sockpair
(protocol-connect "PAIR" "tcp://127.0.0.1:5560")
(prinl (msg-recv (car Sockpair)))
(end-sock Sockpair) )
(bye) )
# => Hello World!
pil +
(load "nanomsg.l")
(unless (fork)
(let Sockpair
(protocol-bind "PAIR" "tcp://127.0.0.1:5560")
(prinl (msg-send (car Sockpair) "Hello World!"))
(end-sock Sockpair) )
(bye) )
pil +
(load "nanomsg.l")
(unless (fork)
(let Sockpair
(protocol-bind "PULL" "tcp://127.0.0.1:5560")
(prinl (msg-recv (car Sockpair)))
(end-sock Sockpair) )
(bye) )
# => Hello Pipeline
pil +
(load "nanomsg.l")
(unless (fork)
(let Sockpair
(protocol-connect "PUSH" "tcp://127.0.0.1:5560")
(prinl (msg-send (car Sockpair) "Hello Pipeline"))
(end-sock Sockpair) )
(bye) )
Note: The Surveyor protocol in Nanomsg is buggy, it's possible for this not to work as expected.
pil +
(load "nanomsg.l")
(unless (fork)
(let Sockpair (protocol-bind "SURVEYOR" "tcp://127.0.0.1:5560")
(msg-send (car Sockpair) "Knock knock.")
(prinl (msg-recv (car Sockpair)))
(end-sock Sockpair) )
(bye) )
# => Who's there?
pil +
(load "nanomsg.l")
(unless (fork)
(let Sockpair
(protocol-connect "RESPONDENT" "tcp://127.0.0.1:5560")
(prinl (msg-recv (car Sockpair)))
(msg-send (car Sockpair) "Who's there?")
(end-sock Sockpair) )
(bye) )
# => Knock knock.
Some situations require non-blocking I/O. You can call msg-recv
or msg-send
with a last argument T
to enable non-blocking mode. Be aware NIL
will be returned if EAGAIN
is received during a non-blocking call. You need to manually poll/loop over the socket in this situation.
Usage example:
...
(let Msg (msg-recv (car Sockpair) T)
(when Msg (fifo '*Messages Msg)) )
...
A fixed amount of memory is allocated for each receive buffer. The default setting is 8192
Bytes (8 KiB).
This can be changed with the environment variable NANOMSG_MAX_SIZE
. You can also overwrite the MSG_MAX_SIZE
global constant at runtime.
This library now comes with full unit tests. To run the tests, type:
make check
If you find any bugs or issues, please create an issue.
If you want to improve this library, please make a pull-request.
MIT License Copyright (c) 2015-2020 Alexander Williams, Unscramble license@unscramble.jp