You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
Alex Williams ccd91cd508
Test with PicoLisp 20.6
1 year ago
.github/workflows Test with PicoLisp 20.6 1 year ago
test Add support for Nanomsg v1.1.2 3 years ago
.gitignore Get rid of git submodules. 6 years ago
CHANGELOG.md Update to Nanomsg 1.1.5. Add GitHub Actions workflow. Remove Travis-CI 1 year ago
EXPLAIN.md Bump nanomsg dep to 0.8-beta and add new functions for simplicity 5 years ago
LICENSE Test with PicoLisp 20.6 1 year ago
Makefile Update to Nanomsg 1.1.5. Add GitHub Actions workflow. Remove Travis-CI 1 year ago
README.md Test with PicoLisp 20.6 1 year ago
build.sh Bump nanomsg dep to 0.8-beta and add new functions for simplicity 5 years ago
module.l Test with PicoLisp 20.6 1 year ago
nanomsg.l Test with PicoLisp 20.6 1 year ago
test.l Add support for Nanomsg v1.1.2 3 years ago

README.md

Nanomsg FFI bindings for PicoLisp

GitHub release Dependency Dependency Build status

Nanomsg FFI bindings for PicoLisp.

The following protocols are supported:

  1. REQ/REP
  2. PUB/SUB
  3. BUS
  4. PAIR
  5. PUSH/PULL (PIPELINE)
  6. SURVEYOR/RESPONDENT

Requirements

  • PicoLisp 64-bit v17.12+
  • Tested up to PicoLisp v20.6.29, see test runs
  • Git
  • UNIX/Linux development/build tools (gcc, make/gmake, etc..)

Explanation

To learn more about PicoLisp and this Nanomsg library, please read the EXPLAIN.md document.

Getting started

This binding relies on the Official Nanomsg C Library, compiled as a shared library.

  1. Type make to pull and compile the Official Nanomsg C Library.
  2. Include nanomsg.l in your project
  3. Try the example below

Linking and Paths

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.

Updating

To keep everything updated, type:

git pull && make clean && make

Usage

Only the following functions are considered public:

  • protocol-bind: bind a REP, PUB, BUS, PAIR, PULL, or SURVEYOR socket (inproc, ipc, tcp)
  • protocol-connect: connect to a REQ, SUB, BUS, PAIR, PUSH, RESPONDENT socket (inproc, ipc, tcp)
  • end-sock: shutdown and close a socket
  • msg-recv: receive a message (blocking/non-blocking)
  • msg-send: send a message (blocking/non-blocking)
  • subscribe: subscribe to a PUB/SUB topic
  • unsubscribe: unsubscribe from a PUB/SUB topic

Note: These functions are not namespace local symbols, which means they would redefine symbols with the same name in the 'pico namespace.

Error handling

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")

Example (REQ/REP)

Server

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?

Client

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!

Example (PUB/SUB)

Server

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!

Client

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) )

Example (BUS)

Server

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!

Client

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) )

Example (PAIR)

Server

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!

Client

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) )

Example (PUSH/PULL) - PIPELINE

Server

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

Client

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) )

Example (SURVEYOR/RESPONDENT)

Note: The Surveyor protocol in Nanomsg is buggy, it's possible for this not to work as expected.

Server

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?

Client

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.

Non-blocking I/O

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)) )
...

Receive buffer size

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.

Testing

This library now comes with full unit tests. To run the tests, type:

make check

Contributing

If you find any bugs or issues, please create an issue.

If you want to improve this library, please make a pull-request.

License

MIT License Copyright (c) 2015-2020 Alexander Williams, Unscramble license@unscramble.jp