pynng icon indicating copy to clipboard operation
pynng copied to clipboard

Pair1 example extended

Open MauiJerry opened this issue 5 years ago • 2 comments

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

MauiJerry avatar Jul 25 '19 02:07 MauiJerry

Hi @MauiJerry, thanks for your interest in the library and for opening an issue. You've got a good point that the docs could make it more clear what a polyamorous pair socket does when you call send on the socket instead of a pipe.

Probably when using a polyamorous pair socket that has multiple connections socket.send() shouldn't be called, since it's hard to reason about where it goes. Using recv_msg() and then calling msg.pipe.send() like you've done is a great strategy. Alternatively, you can access a list of active pipes via socket.pipes directly, and use the remote_address property of the pipe to see who the remote node is.

P. S., I made a small edit to your post to make the code format as python.

codypiersall avatar Aug 01 '19 01:08 codypiersall

Thanks... nice to see the python technique for sharing code here. I'll try to remember it. I have this working nicely on my rPi project, with a PubSub channel sending out updates from Server, that listens on the Pair1 ... although it currently only works using 127.... fixed address. on my TODO is getting zeroconfig working so i can use a name in my code and have the clients on PC.

MauiJerry avatar Aug 01 '19 04:08 MauiJerry