Giter Site home page Giter Site logo

pynng's Introduction

This is pynng.

MIT License PyPI Version smoketest Build docs

Ergonomic bindings for nanomsg next generation (nng), in Python. pynng provides a nice interface on top of the full power of nng. nng, and therefore pynng, make it easy to communicate between processes on a single computer or computers across a network. This library is compatible with Python ≥ 3.6. nng is the rewriting of Nanomsg, which is the spiritual successor to ZeroMQ.

Goals

Provide a Pythonic, works-out-of-the box library on Windows and Unix-y platforms. Like nng itself, the license is MIT, so it can be used without restriction.

Installation

On Windows, MacOS, and Linux, the usual

pip3 install pynng

should suffice. Note that on 32-bit Linux and on macOS no binary distributions are available, so CMake is also required.

Building from the GitHub repo works as well, natch:

git clone https://github.com/codypiersall/pynng
cd pynng
pip3 install -e .

(If you want to run tests, you also need to pip3 install trio curio pytest pytest-asyncio pytest-trio pytest-curio, then just run pytest test.)

pynng might work on the BSDs as well. Who knows!

Using pynng

Using pynng is easy peasy:

from pynng import Pair0

s1 = Pair0()
s1.listen('tcp://127.0.0.1:54321')
s2 = Pair0()
s2.dial('tcp://127.0.0.1:54321')
s1.send(b'Well hello there')
print(s2.recv())
s1.close()
s2.close()

Since pynng sockets support setting most parameters in the socket's __init__ method and is a context manager, the above code can be written much shorter:

from pynng import Pair0

with Pair0(listen='tcp://127.0.0.1:54321') as s1, \
        Pair0(dial='tcp://127.0.0.1:54321') as s2:
    s1.send(b'Well hello there')
    print(s2.recv())

Using pynng with an async framework

Asynchronous sending also works with

curio, trio and asyncio. Here is an example using trio:

import pynng
import trio

async def send_and_recv(sender, receiver, message):
    await sender.asend(message)
    return await receiver.arecv()

with pynng.Pair0(listen='tcp://127.0.0.1:54321') as s1, \
        pynng.Pair0(dial='tcp://127.0.0.1:54321') as s2:
    received = trio.run(send_and_recv, s1, s2, b'hello there old pal!')
    assert received == b'hello there old pal!'

Many other protocols are available as well:

  • Pair0: one-to-one, bidirectional communication.
  • Pair1: one-to-one, bidirectional communication, but also supporting polyamorous sockets
  • Pub0, Sub0: publish/subscribe sockets.
  • Surveyor0, Respondent0: Broadcast a survey to respondents, e.g. to find out what services are available.
  • Req0, Rep0: request/response pattern.
  • Push0, Pull0: Aggregate messages from multiple sources and load balance among many destinations.

Examples

Some examples (okay, just two examples) are available in the examples directory.

Git Branch Policy

The only stable branch is master. There will never be a git push -f on master. On the other hand, all other branches are not considered stable; they may be deleted, rebased, force-pushed, and any other manner of funky business.

pynng's People

Contributors

andrei-pozolotin avatar codypiersall avatar dahlia avatar deets avatar geronimo-iia avatar liu-kan avatar matthiasharrer avatar mlasch avatar mprat avatar muthukumarclay avatar neachdainn avatar raphaelahrens avatar regcs avatar sec42 avatar wtfuzz avatar xzz53 avatar yamrzou avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pynng's Issues

avoid sleep() calls in documentation examples

I'm pretty sure this is only an issue for sync versions but I'm seeing many cases that seem to point to entered contexts not having waited for the objects to be fully "ready" due to start()ing threads without waiting on any "I'm ready" event from the thread. Example:

with Bus0(listen=address, recv_timeout=100) as s0, \
        Bus0(dial=address, recv_timeout=100) as s1, \
        Bus0(dial=address, recv_timeout=100) as s2:
    # let all connections be established
    time.sleep(0.05)

If that is truly unavoidable or inefficient it may be advisable to give a more explicit warning for all sync calls in the documentation, or to provide a helper in the library to wait_ready(s0, s1, s2) that abstracts away the ugly sleeps (and maybe use something more reliable like an assertion at the end to make sure the wait was long enough, or a cycle with timeout, etc)

Ctrl+C does not interrupt Socket.recv or Socket.send

The normal behavior of Python applications is to be able to hit Ctrl+C to interrupt the main thread. However, pynng breaks this expectation for Socket.recv() and Socket.send(). I'm not confident that I've found the underlying issue in nng yet, but I believe (and could be wrong, I haven't attempted a patch yet) that this is related to the use of some pthread_cond_wait, rather than actually restarting the recv() system calls.

local_address and remote_address options do not work on dialers and listeners.

The following fails with a pynng.NotSupported exception:

with pynng.Pair1(listen='tcp://127.0.0.1:12321') as s:
print(s.listeners[0].local_address)

I need to figure out whether this is a bug in nng (the man pages indicate that requesting local_address on listeners should work) or whether I'm using it wrong. I have a slight suspicion that NNG_OPT_LOCADDR and NNG_OPT_REMADDR are actually supposed to work on nng_pipes, not nng_dialer and nng_listener. The tricky thing, if that's the case, is that it's not straightforward to grab the pipe associated with a listener or dialer using the public API. My current guess is that this is just a docs bug in nng, and the intention is that this only applies to a pipe, not listener or dialer.

Is there some way to uninstall pynng?

I just installed it on my MAC. When i execute python3 -m pip uninstall pynng and pip3 uninstall pynng. They showed that Can't uninstall 'pynng'. No files were found to uninstall.

pub/sub example fails

tried to run on python 3.6 with version 0.4.0:

import time
from pynng import Pub0, Sub0, Timeout

address = 'tcp://127.0.0.1:31313'
with Pub0(listen=address) as pub, \
        Sub0(dial=address, recv_timeout=100) as sub0, \
        Sub0(dial=address, recv_timeout=100) as sub1, \
        Sub0(dial=address, recv_timeout=100) as sub2, \
        Sub0(dial=address, recv_timeout=100) as sub3:

    sub0.subscribe(b'wolf')
    sub1.subscribe(b'puppy')
    # The empty string matches everything!
    sub2.subscribe(b'')
    # sub3 is not subscribed to anything
    # make sure everyone is connected
    time.sleep(0.05)

    pub.send(b'puppy: that is a cute dog')
    pub.send(b'wolf: that is a big dog')

    print(sub0.recv())  # prints b'wolf...' since that is the matching message
    print(sub1.recv())  # prints b'puppy...' since that is the matching message

    # sub2 will receive all messages (since empty string matches everything)
    print(sub2.recv())  # prints b'puppy...' since it was sent first
    print(sub2.recv())  # prints b'wolf...' since it was sent second

    try:
        sub3.recv()
        assert False, 'never gets here since sub3 is not subscribed'
    except Timeout:
        print('got a Timeout since sub3 had no subscriptions')

got:

b'wolf: that is a big dog'
b'puppy: that is a cute dog'
b'puppy: that is a cute dog'
Traceback (most recent call last):
  File "tpnng.py", line 27, in <module>
    print(sub2.recv())  # prints b'wolf...' since it was sent second
  File "/home/osaro/mk/tpnng/venv/lib/python3.6/site-packages/pynng/nng.py", line 413, in recv
    check_err(ret)
  File "/home/osaro/mk/tpnng/venv/lib/python3.6/site-packages/pynng/exceptions.py", line 201, in check_err
    raise exc(string, err)
pynng.exceptions.Timeout: Timed out

ARM (Raspberry Pi 4) error on import: undefined symbol: __atomic_fetch_sub_8

Hi,

I was trying to use pynng on a raspberry pi 4 running 32bit raspbian buster and it compiled and installed just fine. I however got the following error when importing pynng:

Python 3.7.3 (default, Apr  3 2019, 05:39:12) 
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pynng
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/pi/oprint/lib/python3.7/site-packages/pynng/__init__.py", line 3, in <module>
    from ._nng import lib, ffi
ImportError: /home/pi/oprint/lib/python3.7/site-packages/pynng/_nng.abi3.so: undefined symbol: __atomic_fetch_sub_8

I found a similar problem in a github issue from opencv (opencv/opencv#15278). One proposed workaround was to preload libatomic, which indeed worked:

(oprint) pi@mprint:~ $ LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1 python
Python 3.7.3 (default, Apr  3 2019, 05:39:12) 
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pynng
>>> 

There is also a related issue+merged PR in the upstream nng repo: nanomsg/nng#1195

This however did not fix the problem for me when updating the nng_rev to the latest master. Also it seems the problem was build related and not occuring during runtime.

I am struggling with understanding how pynng wraps nng and how to further debug the issue. Any help appreciated :)

Support NNG Contexts

NNG Contexts are probably the feature that I am personally most excited about for nng, as compared to nanomsg. In fact, the reason I tackled the aio issue was because I sat down to write support for nng_ctx and discovered there wasn't a synchronous version. Support for contexts will be coming soon; I don't think anything about the implementation will be particularly tricky, so it will just be a function of the amount of time I can spend on it.

Support nng_aio

We need an interface for nng_aio. Initially I'd like to just support registering Python callbacks, but eventually it would be nice to be able to operate with Python event loops like trio.

The tricky bit will be enabling registering Python functions, since naturally nng registers C functions.

Deadlock triggered in test_can_send_from_pipe

There are intermittent deadlocks(?) when the test test_can_send_from_pipe runs. This causes testing to be a pain, and also prevents CI from being useful at all.

I suspect (but am really not sure) that this is related to a race condition between pipe callbacks being called and a socket closing. An unlikely but possible outcome is that libnng has a deadlock. Most likely it's on our end though.

We could make the Appveyor builds more efficient

Since Python 3.5, 3.6, and 3.7 use the same version of the Visual Studio compiler, we could build the nng library a single time, and cut down on build time.

We'd still need separate runs for 32-bit vs 64-bit builds.

Support TLS connections

NNG can be built with support for TLS connections using mbedTLS. We should support this in one way or another. I would like the default install of pynng to include the ability to make secure connections. However, there are a few points to work out:

  • I don't think that nng supports linking to mbedTLS statically. Usually this is better anyway, since it's especially nice to be able to upgrade security libraries without rebuilding everything else, but on the other hand it's nice to be certain that everything can work with the normal python setup.py install incantation.
  • If we don't link statically, binary wheels will not work when mbedTLS is not present.

I want to tackle #10 first, because I think that will make developing this easier.

More thinking needs to go into this...

Subscriber don't receive a few first message or don't receive anything

Hello.

I see pubsub always missing a few first messages or sometimes don't recieve messages at all. Please find my pub and sub scripts below with a log.

Is it possible to implement reliable message delivery?

I very like nng ideas (like surveyor/respondent and push/pull), hope it will grow with reliability enogh to use!

There where three publisher runs. At first subscriber recieves messages from 2nd, at second try it missed all 13 messages and at third try it starts recieving from 3rd one. In all of this I've started subscriber before publisher.

subscriber.py
import asyncio, pynng

async def subscriber():
    sub = pynng.Sub0(dial="tcp://localhost:5555")
    sub.subscribe(b"")
    while True:
        incoming = await sub.arecv()
        print(f"incoming: {incoming}")

asyncio.get_event_loop().run_until_complete(subscriber())
publisher.py
import asyncio, pynng

async def publisher():
    pub = pynng.Pub0(listen="tcp://localhost:5555")
    count = 1
    while True:
        msg = str(count).encode("utf-8")
        print(f"outgoing: {msg}")
        pub.send(msg)
        count += 1
        await asyncio.sleep(1)

asyncio.get_event_loop().run_until_complete(publisher())
$ python publisher.py
╭─khassanov@32vd ~/Workspace/
╰─$ python publisher.py
outgoing: b'1'
outgoing: b'2'
outgoing: b'3'
outgoing: b'4'
KeyboardInterrupt
╭─khassanov@32vd ~/Workspace/
╰─$ python publisher.py
outgoing: b'1'
outgoing: b'2'
outgoing: b'3'
outgoing: b'4'
outgoing: b'5'
outgoing: b'6'
outgoing: b'7'
outgoing: b'8'
outgoing: b'9'
outgoing: b'10'
outgoing: b'11'
outgoing: b'12'
outgoing: b'13'
KeyboardInterrupt
╭─khassanov@32vd ~/Workspace/
╰─$ python publisher.py
outgoing: b'1'
outgoing: b'2'
outgoing: b'3'
outgoing: b'4'
outgoing: b'5'
KeyboardInterrupt
$ python subscriber.py
╭─khassanov@32vd ~/Workspace/
╰─$ python subscriber.py
incoming: b'2'
incoming: b'3'
incoming: b'4'
incoming: b'3'
incoming: b'4'
incoming: b'5'

s1.send(b'') causes pynng.exceptions.NoMemory: Out of memory

from pynng import Pair0

with Pair0(listen='tcp://127.0.0.1:54321') as s1, \
        Pair0(dial='tcp://127.0.0.1:54321') as s2:
    s1.send(b'')
    print(s2.recv())
Traceback (most recent call last):
  File "C:/development/pythondev/test/demo.py", line 6, in <module>
    print(s2.recv())
  File "C:\development\pythondev\test\venv\lib\site-packages\pynng\nng.py", line 451, in recv
    check_err(ret)
  File "C:\development\pythondev\test\venv\lib\site-packages\pynng\exceptions.py", line 201, in check_err
    raise exc(string, err)
pynng.exceptions.NoMemory: Out of memory

Fix Travis Docker build

The Docker build script naively assumes that the correct repository to clone is always https://github.com/codypiersall/pynng. This is fine for branches on this repository, but for pull requests it is the incorrect URL. This causes pull requests to not actually run in CI.

This can be fixed by having the Travis directory mounted in Docker, and then building from the mounted directory.

Use manylinux Docker images instead of our own Docker image

The only thing (as far as I remember...) keeping us on using our own docker image (codypiersall/manylinux1-pynng) is cmake. But it turns out cmake can just be installed from pip and doesn't need to be built from source; this might make CI runs faster, but really the reason is that it just seems nicer to use a well-known docker image.

asend(asyncio) + send_timeout behave strangely

Hi,

I am not sure if I am doing something wrong or how this is supposed to be used, but I found the following issue:

I had plain synchronous code which was using a send/receive timeout to avoid blocking indefinitely. I am running these examples without the server running to force the timeout.

import pynng

socket = pynng.Req0(dial='tcp://127.0.0.1:54321', send_timeout=1000, recv_timeout=1000)

def send(command):
    socket.send(command)
    return socket.recv()

send(b'test')

This was working as expected and gave me the following exception when the timeout was hit:

pynng.exceptions.Timeout: Timed out

I then converted my code to use asyncio and the corresponding asend / arecv functions.

import asyncio
import pynng

socket = pynng.Req0(dial='tcp://127.0.0.1:54321', send_timeout=1000, recv_timeout=1000)

async def send(command):
    await socket.asend(command)
    return await socket.arecv()

asyncio.run(send(b'test'))

In this case the asend function just returns after the timeout but does not throw any timeout exception or otherwise indicates that the timeout was hit. This in turn of course leads to a bad state exception on the arecv:

pynng.exceptions.BadState: Incorrect state

Am I missing something here or is this not working as expected?

Thanks a lot :)

Messages being dropped or how to send reliably

I'd like to use polyamorous Pair1 over unix domain sockets and would like to make use of flow control on the unix domain socket, i.e. if the receivers cannot process messages fast enough the sender should not be allowed to put further messages into the socket. So far, I fail to achieve this, but instead messages are simply dropped.

send_buffer_size and receive_buffer_size I understand to be within nng code not influencing buffering in the kernel.

from pynng import Pair1

address = f'ipc://nng.socket'
with Pair1(polyamorous=True, send_buffer_size=1, recv_buffer_size=1, recv_max_size=0) as s0, \
     Pair1(polyamorous=True, send_buffer_size=1, recv_buffer_size=1, recv_max_size=0) as s1:
    s0.listen(address)
    s1.dial(address)
    send_idx = recv_idx = 0
    while True:
        print(f'SEND {send_idx}')
        s1.send(str(send_idx).encode('ascii'))
        print(f'SEND {send_idx} DATA')
        s1.send(1 * 2 ** 20 * b'0')
        send_idx += 1

        print(f'SEND {send_idx}')
        s1.send(str(send_idx).encode('ascii'))
        print(f'SEND {send_idx} DATA')
        s1.send(1 * 2 ** 20 * b'0')
        send_idx += 1

        print(f'RECV {recv_idx}')
        data = s0.recv()
        assert len(data) != 1 * 2 ** 20 and len(data) == len(str(recv_idx)), \
            (len(data), data[0], recv_idx)
        assert data.decode('ascii') == str(recv_idx), (data, recv_idx)

        print(f'RECV {recv_idx} DATA')
        print(f'RECV {recv_idx}')
        data = s0.recv()
        assert len(data) == 1 * 2 ** 20
        recv_idx += 1

Given that I'm sending twice as much as I'm receiving, I'd expect this to block at some point during send. Instead messages are dropped:

...
RECV 4 DATA
RECV 4
SEND 10
SEND 10 DATA
SEND 11
SEND 11 DATA
RECV 5
Traceback (most recent call last):
  File "asyn.py", line 27, in <module>
    (len(data), data[0], recv_idx)
AssertionError: (1048576, 48, 5)

I tried to use select.select() to determine whether a socket is ready for sending. However, this seems not to be the case, i.e. the call to select does not return.

import select
from pynng import Pair1

address = f'ipc://nng.socket'
with Pair1(polyamorous=True, send_buffer_size=1, recv_buffer_size=1, recv_max_size=0) as s0, \
     Pair1(polyamorous=True, send_buffer_size=1, recv_buffer_size=1, recv_max_size=0) as s1:
    s0.listen(address)
    s1.dial(address)
    send_idx = recv_idx = 0
    while True:
        print(f'SEND {send_idx}')
        select.select([], [s1.send_fd], [])  # wait for socket to be ready
        s1.send(str(send_idx).encode('ascii'))
        print(f'SEND {send_idx} DATA')

What is the correct way to send messages reliably and is there way to make use of unix domain socket / tcp socket flow control?

PUB/SUB example extended

It seems like the PUB/SUB example could be improved (just a little bit)-- I'm getting confused that current example of pynng SUB + PUB code is all running in the same program (wouldn't this usually be running on 2 different machines, or multiple really, in practice?) I'd like to have 2 snippets of code that should be executed in separate threads/shells. The order of operation would be something like this....

(1) Run pynng_sub.py
(2) Run pynng_pub.py
(3) Results/msg would flow into sub based on the topics

I tried coming up with something but I'm getting some "pynng.exceptions.Timeout: Timed out" errors on the sub side...that leads me to another issue/topic related to this pattern...

Is there an elegant way to coordinate the PUB/SUB timing so the SUB is ready and will receive all the msg from PUB-- this is akin to the "Hello" msg sent to get acknowledgement that PUB and SUB are talking to each other (zmq docs mentioned this but didn't exactly show it completely, I can pull the link if it helps explain what I'm looking for better)...I'd love to know the right way to go about this so I don't hack something that's not optimal or resilient in the future.

Fix tests on Azure

Several tests fail on Azure, particularly on Mac. There are a couple things I want to do to make things better:

  1. Add send/recv timeouts to all sockets in all tests, so Azure tests will actually fail instead of just timing out after an hour.
  2. Fix the actual tests so they don't fail.

examples/pair1_async.py uses deprecated method

Trying out the pair1_async example after installing Trio (latest = 0.12.0) i got the message ...

TrioDeprecationWarning: trio.run_sync_in_worker_thread is deprecated since Trio 0.12.0; use trio.to_thread.to_thread_run_sync instead (python-trio/trio#810)

but be aware that deprecated suggestion is wrong, due to trio/to_thread importing the function as run_sync() so the updated line should be

   stuff = await trio.to_thread.run_sync(input, cancellable=True)

Race condition with nng_pipe_cb and live_sockets

With pynng 0.4.0 and Python 3.7.1 there seems to be a race condition involving _nng_pipe_cb.

Traceback (most recent call last):
  File "/venv/lib/python3.7/site-packages/pynng/nng.py", line 1211, in _nng_pipe_cb
    sock = _live_sockets[sock_id]
  File "/usr/lib/python3.7/weakref.py", line 137, in __getitem__
    o = self.data[key]()
KeyError: 139787429631984

@codypiersall Do you have any suggestions what could lead to a socket being expected in _live_sockets but not being there anymore or not yet and how to debug this?

So far I'm failing to produce a minimal working example. The code involves async generators with Pair0 sockets used as context managers and the race condition is triggered independent of whether arecv/asend or recv/send are being used.

Moving https://github.com/codypiersall/pynng/blob/master/pynng/nng.py#L308 to https://github.com/codypiersall/pynng/blob/master/pynng/nng.py#L295 seems to reduce the occurrence but does not eliminate the race condition.

trio example shows deprecation warnings with Trio >= 0.15.0

Trying the example for trio on the top-level README file in section, I get:

/usr/local/lib/python3.7/site-packages/pynng/_aio.py:71: TrioDeprecationWarning: trio.hazmat is deprecated since Trio 0.15.0; use trio.lowlevel instead (https://github.com/python-trio/trio/issues/476)
  token = trio.hazmat.current_trio_token()
/usr/local/lib/python3.7/site-packages/pynng/_aio.py:72: TrioDeprecationWarning: trio.hazmat is deprecated since Trio 0.15.0; use trio.lowlevel instead (https://github.com/python-trio/trio/issues/476)
  task = trio.hazmat.current_task()
/usr/local/lib/python3.7/site-packages/pynng/_aio.py:94: TrioDeprecationWarning: trio.hazmat is deprecated since Trio 0.15.0; use trio.lowlevel instead (https://github.com/python-trio/trio/issues/476)
  await trio.hazmat.wait_task_rescheduled(abort_fn)
/usr/local/lib/python3.7/site-packages/pynng/_aio.py:75: TrioDeprecationWarning: trio.hazmat is deprecated since Trio 0.15.0; use trio.lowlevel instead (https://github.com/python-trio/trio/issues/476)
  token.run_sync_soon(trio.hazmat.reschedule, task)

I have Trio v0.15.1 installed.

Pair1 example extended

while learning about Pair1, I played with the example a bit, providing some extra examples and tests. Thought it might be nice to share that code so....

#from the docs page https://pynng.readthedocs.io/en/latest/core.html#available-protocols
# with some mods
# Pair1 allows single Server/Listener to connect bi-directionally with multiple Client/Dialers
# it does NOT operate as a Publisher in that a listner.send() goes to ??
import sys, traceback
from pynng import Pair1, Timeout
print("begin Pair 1 polyamorous test")

address = 'tcp://127.0.0.1:12343'
with Pair1(listen=address, polyamorous=True, recv_timeout=100) as s0, \
        Pair1(dial=address, polyamorous=True, recv_timeout=100) as s1, \
        Pair1(dial=address, polyamorous=True, recv_timeout=100) as s2:
    print("opened all 3")
    s0.send(b'hi everybody!')
    s1.send(b'hello from s1')
    s2.send(b'hello from s2')
    print("sent all three")
    print("recv_msg on s0")
    msg1 = s0.recv_msg()
    print(msg1.bytes)  # prints b'hello from s1'

    msg2 = s0.recv_msg()
    print(msg2.bytes)  # prints b'hello from s2'
    
    print("recv on s1:")
    msg01 = s1.recv()
    print(msg01)  # prints b'hello from s1'

    try:
        print("recv on s2")
        msg02 = s2.recv()
        print(msg02)  # prints b'hello from s2'
    except Timeout:
        print("Timeout on S2 waiting to hear from s0")

    print("send single msg responses")
    msg1.pipe.send(b'hey s1')
    msg2.pipe.send(b'hey s2')
    print(s2.recv())  # prints b'hey s2'
    print(s1.recv())  # prints b'hey s1'
    
    # beyond first msg, repeats will share the Pipe but not data
    s1.send(b'more from s1')
    morMsg = s0.recv_msg()
    print("morMsg: ")
    print(morMsg.bytes)
    if morMsg.pipe == msg1.pipe:
        print ("msg1 and morMsg share pipe")
    else:
        print ("msg1 and morMsg do NOT share pipe")
    print("and msg1 still says:")
    print(msg1.bytes)
    
    print("what if s0 does recv instead of recvMsg?")
    s1.send(b'again from s1')
    more = s0.recv()
    print(more)
#    print("It works, we just dont get the Message info")
    
    print("Pair1 with both listen and dial should throw exception")
    # pynng Pair1 has no code to recognize this error, allowing both arguments
    # however the underlying Socket should throw an AddressInUse exception
    try:
        with Pair1(dial=address, listen=address, polyamorous=True, recv_timeout=100) as s3:
            s3.send(b'hello out there')
            msg = s0.recv_msg()
            print("rceve on s0")
            print(msg.bytes)
            s3.send(b'hello out there')
            msg = s3.recv_msg()
            print("rceve on s3")
            print(msg.bytes)
    except:
        print("caught something", sys.exc_info()[0])
        traceback.print_exc()#sys.exc_info()[2].print_tb()
        #raise
    
print("End Pair1 test")

Telnet'ing into port used by Req0/Rep0 causes a block

Hi Cody, I have a very simple use case utilizing the Req0/Rep0 pattern (pynng 0.4.1 / python 3.6.3) shown below:

def reply():
    import pynng
    socket = pynng.Rep0()
    socket.listen("tcp://127.0.0.1:9935")

    while True:
        m = socket.recv()
        print(f"{m}")
        socket.send(b"world")

def request():
    import pynng

    socket = pynng.Req0()
    socket.dial("tcp://127.0.0.1:9935")

    count = 0
    while True:
        try:
            print("sending")
            socket.send(b"hello")
            m = socket.recv()
            print(m)
            count = count + 1
            print(f"count: {count}")
        except Exception as e:
            print(e)
            print("retrying")

Under normal circumstances, this works fine (i.e. start reply(), followed by request()).

However, I encountered an issue that I can't seem to resolve. The scenario can be repeated like so:

  1. start reply()
  2. telnet 127.0.0.1 9935. I get a response "SP1". Leave this telnet window open
  3. start request()
  4. request() is blocked at socket.send until I randomly enter ~8 characters in the telnet window @ 2. This is will result is a "Connection to host lost" message.
  5. request() functions normally after
    NB: As long as the telnet is left in the state @ 2, the request @ 4 will block indefinitely which is a problem

Is there something that I am missing? A similar code in pyzmq works. Any help is deeply appreciated.

Unreliable package response time

I´m having issues getting a reliable response time for packages sent and received in a python application. Using Pair1 to listen on a Windows 10 machine for connections from a Ubuntu machine. Packages are sent from Windows to the Ubuntu machine, where they are immediately send back as response. Response time for small packages (<58 bytes paylod) is slow (around 2-3ms) and as expected. However payloads >=58 bytes are giving an unreliable response times (3ms- 300ms) and even some packages are retransmitted.
Not sure if that behaviour is related to pynng/nng or more an issue of the OS.(TCP_NODELAY is True).
Do you have any idea what could cause this?

Is there a way to connect local server?

Hi!

I have installed pynng in a local server and I am able to send and receive in the same server.
Is there any way to communicate and send data to another local server connect within the network ?
For example send data from 192.168.1.58 server to 192.168.1.59 server.

I tried but I am getting "pynng.exceptions.AddressInvalid: Address invalid" Error

PIP installation fails (Win10)

Installation of pynng via pip fails for my Win10 machine (Version 10.0.17134 Build 17134). Before being able to install at all, I had to run pip install cmake (otherwise, cmake would be an unrecognized command).

Is the problem a wrong/incomplete installation of Visual Studio 14 2015 Win64, or is there some error in the setup.py?

The output of the command prompt (pip is run as administrator):

C:\>pip install pynng
Collecting pynng
  Using cached https://files.pythonhosted.org/packages/43/5f/2b31533f9d44fe568a49bb309ae36f3c8e32a62008826939191885b46b94/pynng-0.1.2.tar.gz
Requirement already satisfied: cffi in c:\program files\python37\lib\site-packages (from pynng) (1.11.5)
Requirement already satisfied: pycparser in c:\program files\python37\lib\site-packages (from cffi->pynng) (2.19)
Installing collected packages: pynng
  Running setup.py install for pynng ... error
    Complete output from command "c:\program files\python37\python.exe" -u -c "import setuptools, tokenize;__file__='C:\\Users\\lcnittl\\AppData\\Local\\Temp\\pip-install-0b5n25ym\\pynng\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record C:\Users\lcnittl\AppData\Local\Temp\pip-record-o72gsi5f\install-record.txt --single-version-externally-managed --compile:
    Warning: 'classifiers' should be a list, got type 'tuple'
    running install
    running build
    running build_py

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng>if {"Visual Studio 14 2015 Win64"} == {} (
    echo.ERROR: You must provide the correct CMake compiler generator.
     goto :end
    )

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng>pushd .

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng>rmdir /s /q nng\build
    The system cannot find the file specified.

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng>if not exist nng (
    git clone https://github.com/nanomsg/nng nng
     pushd nng
     git checkout 6c334f3
     popd
    )

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng>mkdir nng\build

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng>cd nng\build   && cmake -G "Visual Studio 14 2015 Win64" ..   && cmake --build . --config Release
    -- Selecting Windows SDK version  to target Windows 10.0.17134.
    -- The C compiler identification is MSVC 19.0.24210.0
    -- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/x86_amd64/cl.exe
    -- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/x86_amd64/cl.exe -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Detecting C compile features
    -- Detecting C compile features - done
    -- Could NOT find UnixCommands (missing: BASH CP MV RM)
    -- Check if the system is big endian
    -- Searching 16 bit integer
    -- Looking for sys/types.h
    -- Looking for sys/types.h - found
    -- Looking for stdint.h
    -- Looking for stdint.h - found
    -- Looking for stddef.h
    -- Looking for stddef.h - found
    -- Check size of unsigned short
    -- Check size of unsigned short - done
    -- Using unsigned short
    -- Check if the system is big endian - little endian
    -- Looking for pthread.h
    -- Looking for pthread.h - not found
    -- Found Threads: TRUE
    -- Looking for InitializeConditionVariable
    -- Looking for InitializeConditionVariable - found
    -- Looking for snprintf
    -- Looking for snprintf - found
    -- Looking for strlcat
    -- Looking for strlcat - not found
    -- Looking for strlcpy
    -- Looking for strlcpy - not found
    -- Looking for strnlen
    -- Looking for strnlen - found
    -- Looking for strcasecmp
    -- Looking for strcasecmp - not found
    -- Looking for strncasecmp
    -- Looking for strncasecmp - not found
    -- Building static libs
    -- Test tls disabled (unconfigured)
    -- Test wss disabled (unconfigured)
    -- Test wssfile disabled (unconfigured)
    -- Test zt disabled (unconfigured)
    -- The CXX compiler identification is MSVC 19.0.24210.0
    -- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/x86_amd64/cl.exe
    -- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/x86_amd64/cl.exe -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    CMake Error at CMakeLists.txt:497 (add_subdirectory):
      add_subdirectory given source "docs/man" which is not an existing
      directory.


    -- Configuring incomplete, errors occurred!
    See also "C:/Users/lcnittl/AppData/Local/Temp/pip-install-0b5n25ym/pynng/nng/build/CMakeFiles/CMakeOutput.log".
    See also "C:/Users/lcnittl/AppData/Local/Temp/pip-install-0b5n25ym/pynng/nng/build/CMakeFiles/CMakeError.log".

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng\nng\build>popd
    creating build
    creating build\lib.win-amd64-3.7
    creating build\lib.win-amd64-3.7\pynng
    copying pynng\exceptions.py -> build\lib.win-amd64-3.7\pynng
    copying pynng\nng.py -> build\lib.win-amd64-3.7\pynng
    copying pynng\__init__.py -> build\lib.win-amd64-3.7\pynng
    creating build\lib.win-amd64-3.7\test
    copying test\test_api.py -> build\lib.win-amd64-3.7\test
    copying test\test_options.py -> build\lib.win-amd64-3.7\test
    copying test\test_protocols.py -> build\lib.win-amd64-3.7\test
    copying test\__init__.py -> build\lib.win-amd64-3.7\test
    running build_ext
    generating cffi module 'build\\temp.win-amd64-3.7\\Release\\pynng._nng.c'
    creating build\temp.win-amd64-3.7
    creating build\temp.win-amd64-3.7\Release

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng>if {"Visual Studio 14 2015 Win64"} == {} (
    echo.ERROR: You must provide the correct CMake compiler generator.
     goto :end
    )

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng>pushd .

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng>rmdir /s /q nng\build

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng>if not exist nng (
    git clone https://github.com/nanomsg/nng nng
     pushd nng
     git checkout 6c334f3
     popd
    )

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng>mkdir nng\build

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng>cd nng\build   && cmake -G "Visual Studio 14 2015 Win64" ..   && cmake --build . --config Release
    -- Selecting Windows SDK version  to target Windows 10.0.17134.
    -- The C compiler identification is MSVC 19.0.24210.0
    -- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/x86_amd64/cl.exe
    -- Check for working C compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/x86_amd64/cl.exe -- works
    -- Detecting C compiler ABI info
    -- Detecting C compiler ABI info - done
    -- Detecting C compile features
    -- Detecting C compile features - done
    -- Could NOT find UnixCommands (missing: BASH CP MV RM)
    -- Check if the system is big endian
    -- Searching 16 bit integer
    -- Looking for sys/types.h
    -- Looking for sys/types.h - found
    -- Looking for stdint.h
    -- Looking for stdint.h - found
    -- Looking for stddef.h
    -- Looking for stddef.h - found
    -- Check size of unsigned short
    -- Check size of unsigned short - done
    -- Using unsigned short
    -- Check if the system is big endian - little endian
    -- Looking for pthread.h
    -- Looking for pthread.h - not found
    -- Found Threads: TRUE
    -- Looking for InitializeConditionVariable
    -- Looking for InitializeConditionVariable - found
    -- Looking for snprintf
    -- Looking for snprintf - found
    -- Looking for strlcat
    -- Looking for strlcat - not found
    -- Looking for strlcpy
    -- Looking for strlcpy - not found
    -- Looking for strnlen
    -- Looking for strnlen - found
    -- Looking for strcasecmp
    -- Looking for strcasecmp - not found
    -- Looking for strncasecmp
    -- Looking for strncasecmp - not found
    -- Building static libs
    -- Test tls disabled (unconfigured)
    -- Test wss disabled (unconfigured)
    -- Test wssfile disabled (unconfigured)
    -- Test zt disabled (unconfigured)
    -- The CXX compiler identification is MSVC 19.0.24210.0
    -- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/x86_amd64/cl.exe
    -- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin/x86_amd64/cl.exe -- works
    -- Detecting CXX compiler ABI info
    -- Detecting CXX compiler ABI info - done
    -- Detecting CXX compile features
    -- Detecting CXX compile features - done
    CMake Error at CMakeLists.txt:497 (add_subdirectory):
      add_subdirectory given source "docs/man" which is not an existing
      directory.


    -- Configuring incomplete, errors occurred!
    See also "C:/Users/lcnittl/AppData/Local/Temp/pip-install-0b5n25ym/pynng/nng/build/CMakeFiles/CMakeOutput.log".
    See also "C:/Users/lcnittl/AppData/Local/Temp/pip-install-0b5n25ym/pynng/nng/build/CMakeFiles/CMakeError.log".

    C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng\nng\build>popd
    building 'pynng._nng' extension
    creating build\temp.win-amd64-3.7\Release\build
    creating build\temp.win-amd64-3.7\Release\build\temp.win-amd64-3.7
    creating build\temp.win-amd64-3.7\Release\build\temp.win-amd64-3.7\Release
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\x86_amd64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -Inng/src "-Ic:\program files\python37\include" "-Ic:\program files\python37\include" "-IC:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.10240.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\8.1\include\shared" "-IC:\Program Files (x86)\Windows Kits\8.1\include\um" "-IC:\Program Files (x86)\Windows Kits\8.1\include\winrt" /Tcbuild\temp.win-amd64-3.7\Release\pynng._nng.c /Fobuild\temp.win-amd64-3.7\Release\build\temp.win-amd64-3.7\Release\pynng._nng.obj
    pynng._nng.c
    C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\x86_amd64\link.exe /nologo /INCREMENTAL:NO /LTCG /DLL /MANIFEST:EMBED,ID=2 /MANIFESTUAC:NO "/LIBPATH:c:\program files\python37\libs" "/LIBPATH:c:\program files\python37\PCbuild\amd64" "/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\LIB\amd64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.10240.0\ucrt\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\8.1\lib\winv6.3\um\x64" Ws2_32.lib Advapi32.lib /EXPORT:PyInit__nng build\temp.win-amd64-3.7\Release\build\temp.win-amd64-3.7\Release\pynng._nng.obj ./nng/build/Release/nng.lib /OUT:build\lib.win-amd64-3.7\pynng\_nng.cp37-win_amd64.pyd /IMPLIB:build\temp.win-amd64-3.7\Release\build\temp.win-amd64-3.7\Release\_nng.cp37-win_amd64.lib
    LINK : fatal error LNK1181: cannot open input file './nng/build/Release/nng.lib'
    error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\BIN\\x86_amd64\\link.exe' failed with exit status 1181

    ----------------------------------------
Command ""c:\program files\python37\python.exe" -u -c "import setuptools, tokenize;__file__='C:\\Users\\lcnittl\\AppData\\Local\\Temp\\pip-install-0b5n25ym\\pynng\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record C:\Users\lcnittl\AppData\Local\Temp\pip-record-o72gsi5f\install-record.txt --single-version-externally-managed --compile" failed with error code 1 in C:\Users\lcnittl\AppData\Local\Temp\pip-install-0b5n25ym\pynng\

Thanks in advance for any help!

What is pynng's license now that we're bundling Mbed TLS?

I initially licensed everything as MIT because I appreciate the freedom and flexibility that it gives users. However, as of merging #52, we are now bundling the Mbed TLS library, which is Apache 2.0 licensed.

My current understanding is that since the Apache 2.0 license is not copyleft, we do not need to license pynng itself under the Apache 2.0 license. However, whenever we build Python wheels and create source distributions, we are bundling Apache 2.0-licensed software. I think that to abide by the Apache 2.0 license of the software we are using, it is sufficient to add a notice that we are using the Mbed TLS library, which is Apache 2.0 licensed.

This is actually relevant, because it is possible that nng will be able to use a different TLS library one day; Garrett has mentioned using BearSSL: nanomsg/nng#300. If this happens and we switch to using it, there would be no non-MIT-licensed dependencies, and we would go back to being unambiguously MIT licensed. But if we actually changed our license to Apache 2.0 and received contributions under that license, we would have to ask contributors if they were okay with also licensing their contributions as MIT license, which is just a hassle.

The upshot is that all pynng contributions will still be MIT licensed, but the default pynng binary with TLS support added will be Apache 2.0 licensed.

I am not a lawyer... does this make sense?

Add `raw` sockets

Currently, there is not a good way to get a raw socket. It can technically be done, but the API is terrible: pass the raw open function to Socket.

I want to do two things: first, remove the _opener argument from Socket. I think that argument is the most confusing footgun in the library. Second, add the Raw version of all the socket classes.

I'm a little worried that there are going to be "too many classes" in the library. I do think the discoverability is better though. The alternative would be to have __init__ take a raw keyword argument, but I think that's a lot easier to miss when reading code than a separate class name.

Once raw mode sockets are added, support for nng_device can be added as well.

pynng does not work on Python 2.7

ldw@ubuntu:$ git clone https://github.com/codypiersall/pynng
Cloning into 'pynng'...
remote: Enumerating objects: 61, done.
remote: Counting objects: 100% (61/61), done.
remote: Compressing objects: 100% (43/43), done.
remote: Total 682 (delta 28), reused 43 (delta 18), pack-reused 621
Receiving objects: 100% (682/682), 146.12 KiB | 261.00 KiB/s, done.
Resolving deltas: 100% (422/422), done.
ldw@ubuntu:
$ cd pynng
ldw@ubuntu:~/pynng$ pip install -e .
Obtaining file:///home/ldw/pynng
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "", line 1, in
File "/home/ldw/pynng/setup.py", line 27
major, minor, *_ = sys.version_info
^
SyntaxError: invalid syntax

----------------------------------------

Command "python setup.py egg_info" failed with error code 1 in /home/ldw/pynng/
ldw@ubuntu:/pynng$ python --version
Python 2.7.15rc1
ldw@ubuntu:
/pynng$ uname -a
Linux ubuntu 4.15.0-29-generic #31-Ubuntu SMP Tue Jul 17 15:39:52 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
ldw@ubuntu:~/pynng$

======================
I want to install pynng on ubuntu18.04 OS with python2.7, but failed with above log info.
Could you help to see what's the issue for the setup.py ?

pip install fails on macOS Mojave

All good just needed cmake. Misread warning as error.

Collecting pynng
  Downloading https://files.pythonhosted.org/packages/1b/fb/23266f32a8dfa1c86991b6315577e95b803061de154725a82e5ff6f800d4/pynng-0.4.0.tar.gz (607kB)
    100% |████████████████████████████████| 614kB 805kB/s 
Collecting cffi (from pynng)
  Using cached https://files.pythonhosted.org/packages/f0/48/5aa4ea664eba26dd5142558d04762f5065c02220b4665b3f7eecb9bb614e/cffi-1.12.3-cp37-cp37m-macosx_10_9_x86_64.whl
Collecting sniffio (from pynng)
  Downloading https://files.pythonhosted.org/packages/b3/82/4bd4b7d9c0d1dc0fbfbc2a1e00138e7f3ab85bc239358fe9b78aa2ab586d/sniffio-1.1.0-py3-none-any.whl
Collecting pycparser (from cffi->pynng)
Installing collected packages: pycparser, cffi, sniffio, pynng
  Running setup.py install for pynng ... error
    Complete output from command /Users/gnguyen/Projects/microservices/.venv/bin/python3 -u -c "import setuptools, tokenize;__file__='/private/var/folders/f0/yk2mvwk92rx0wj1xygs3sjcw000528/T/pip-install-7voii7jk/pynng/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /private/var/folders/f0/yk2mvwk92rx0wj1xygs3sjcw000528/T/pip-record-2sbmtzsy/install-record.txt --single-version-externally-managed --compile --install-headers /Users/gnguyen/Projects/microservices/.venv/include/site/python3.7/pynng:
    /usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/distutils/dist.py:274: UserWarning: Unknown distribution option: 'long_description_content_type'
      warnings.warn(msg)
    running install
    running build
    running build_py
    /private/var/folders/f0/yk2mvwk92rx0wj1xygs3sjcw000528/T/pip-install-7voii7jk/pynng/build_nng.sh: line 24: cmake: command not found
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/private/var/folders/f0/yk2mvwk92rx0wj1xygs3sjcw000528/T/pip-install-7voii7jk/pynng/setup.py", line 142, in <module>
        test_suite='tests',
      File "/Users/gnguyen/Projects/microservices/.venv/lib/python3.7/site-packages/setuptools/__init__.py", line 129, in setup
        return distutils.core.setup(**attrs)
      File "/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/distutils/core.py", line 148, in setup
        dist.run_commands()
      File "/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/distutils/dist.py", line 966, in run_commands
        self.run_command(cmd)
      File "/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/distutils/dist.py", line 985, in run_command
        cmd_obj.run()
      File "/Users/gnguyen/Projects/microservices/.venv/lib/python3.7/site-packages/setuptools/command/install.py", line 61, in run
        return orig.install.run(self)
      File "/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/distutils/command/install.py", line 545, in run
        self.run_command('build')
      File "/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/distutils/cmd.py", line 313, in run_command
        self.distribution.run_command(command)
      File "/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/distutils/dist.py", line 985, in run_command
        cmd_obj.run()
      File "/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/distutils/command/build.py", line 135, in run
        self.run_command(cmd_name)
      File "/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/distutils/cmd.py", line 313, in run_command
        self.distribution.run_command(command)
      File "/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/distutils/dist.py", line 985, in run_command
        cmd_obj.run()
      File "/private/var/folders/f0/yk2mvwk92rx0wj1xygs3sjcw000528/T/pip-install-7voii7jk/pynng/setup.py", line 88, in run
        build_nng_lib()
      File "/private/var/folders/f0/yk2mvwk92rx0wj1xygs3sjcw000528/T/pip-install-7voii7jk/pynng/setup.py", line 80, in build_nng_lib
        subprocess.check_call(cmd, shell=needs_shell)
      File "/usr/local/Cellar/python/3.7.1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/subprocess.py", line 341, in check_call
        raise CalledProcessError(retcode, cmd)
    subprocess.CalledProcessError: Command '['/bin/bash', '/private/var/folders/f0/yk2mvwk92rx0wj1xygs3sjcw000528/T/pip-install-7voii7jk/pynng/build_nng.sh', 'd3bd35ab49ad74528fd9e34cce9016d74dd91943']' returned non-zero exit status 127.

macOS Build

The README says:

This project does not yet know how to build for Mac, because I don't have a Mac to test on. The tricky bit is letting cffi know the correct object file to link to, and ensuring whatever the Mac equivalent of -fPIC is set when compiling.

I just successfully built this on macOS High Sierra without any issues. The only warnings were a series of linker warnings saying that some object files were built for a newer version of macOS than were being linked. I haven't tested the build beyond running pytest but that was also successful. I did not have nng installed on my system before trying to build pynng.

Is there anything else you would like me to do and/or test before you're comfortable saying macOS is supported?

Edit: It only works with Python3 but the errors I am receiving make it seem unlikely that it a Mac-specific issue.

The way we're building the nng library is an abuse of setuptools

Right now we're subclassing the build_py class in order to make sure that the nng library would be built by the time we needed to build an extension, but this was – apparently – a misunderstanding of how setuptools works. I think it is also causing us to build nng twice on all the CI runs, which is unfortunate.

I'm not planning on fixing this immediately, since the current situation is workable and there are more important things to do.

Push0 not reliable in sending and receiving messages

I have a service to implement Push0(listen) to receive messages and a notifier service to send messages as following code:
`
import time
from os.path import expanduser
from pynng import Push0

ipc_path = "ipc://" + expanduser("~") + "/.userdata/rpc/events"
def send_event(event):
with Push0(dial=ipc_path,block_on_dial=True, send_timeout=100, send_buffer_size = 1) as push:
time.sleep(0.01)
push.send((event).to_bytes())

i = 0
while True:
send_event('imap' + str(i))
i+=1
if i == 10:
exit(1)
time.sleep(1)
`
from 10 sent message I receive 2 or 3 messages randomly, (0, 8), (2, 3, 7), (4, 9) and ... I changed parameters such as send_timeout, block_on_dial, send_buffer_size but my result is not changed. can you help me how deal with this issue and fix it?

Enable non-blocking recv()

Am I correct, interpreting that currently it is not possible to receive in a non-blocking way (PUB/SUB mode)?

pynng/pynng/nng.py

Lines 318 to 327 in 4447fd7

def recv(self):
"""recv() on the socket. Allows the nanomsg library to allocate and
manage the buffer, and calls nng_free afterward."""
data = ffi.new('char *[]', 1)
size_t = ffi.new('size_t []', 1)
ret = lib.nng_recv(self.socket, data, size_t, lib.NNG_FLAG_ALLOC)
check_err(ret)
recvd = ffi.unpack(data[0], size_t[0])
lib.nng_free(data[0], size_t[0])
return recvd

The desired feature would use nngs NNG_FLAG_NONBLOCK of nng_recv:
https://nanomsg.github.io/nng/man/v1.1.0/nng_recv.3

If one wanted to implement this, would this require only changes in the python code, or also in the nng libs? (Please consider me an absolute noob in binding architectures)

Associate messages with Pipes in a "best effort" way

We have a failure of associating pipes with messages in some circumstances, which caused #25 to fail in Travis.

I'm not sure how this happened. Pipes getting associated with Sockets is racy–that happens in a separate thread, asynchronously from the main Python thread–but I still don't see how this could happen. According to the nng docs, the event NNG_PIPE_EV_ADD_PRE happens before the pipe is associated with the socket. That made me think that the socket would be unable to receive messages associated with that pipe until after the callback returned.

I imagine the problem is in the bookkeeping somewhere in pynng, but I'm not sure where at this point. I also want to check out nng's source to see how the callbacks get called. If they just get scheduled to run in a different thread (probably unlikely) then this failure makes sense, otherwise I'm not sure what happened, apart from pain and suffering.

Pre-pipe connection rejection at remote socket causes key error on local socket.

The following exception sometimes occurs when a remote socket rejects a local socket's connection:

Traceback (most recent call last):
  File "C:\Users\hern6928\Desktop\CPPAR Client\support\cppar-virtual-env\env\lib\site-packages\pynng\nng.py", line 797, in _nng_pipe_cb
    pipe = sock._pipes[pipe_id]
KeyError: 552720521
From cffi callback <function _nng_pipe_cb at 0x22E14C90>:
Traceback (most recent call last):
  File "C:\Users\hern6928\Desktop\CPPAR Client\support\cppar-virtual-env\env\lib\site-packages\pynng\nng.py", line 797, in _nng_pipe_cb
    pipe = sock._pipes[pipe_id]
KeyError: 552720523```

It also appears that "sock._pipes" sometimes doesn't properly capture the rejected status of the connection, as sometimes it still has children when the attempted connections were rejected.

Cannot integrate with nng

Hi, I have a c subscriber program which subscribes to any topic and a python publisher program using pynng. However, my subscriber program cannot receive anything from the python program.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.