Pynng
Pynng is a Python binding for the nng (nanomsg-next-generation) C library, providing lightweight, high-performance messaging patterns for network communication. It supports both synchronous and asynchronous (asyncio) operations, making it suitable for a wide range of network applications. The current version is 0.9.0, and it generally follows a moderate release cadence, with updates often introducing significant features or improvements.
Common errors
-
error: command 'gcc' failed with exit status 1
cause The `pynng` installation failed to compile the underlying `nng` C library because a C compiler or necessary development headers were not found on the system.fixInstall a C compiler and development headers. For Linux (Debian/Ubuntu): `sudo apt-get install build-essential`. For macOS: `xcode-select --install`. For Windows, consider using WSL or Visual Studio Build Tools. -
AttributeError: 'Socket' object has no attribute 'recv'
cause You are likely trying to call the synchronous `recv()` method on an asynchronous socket (or vice-versa), or you've made a typo. The method names for async operations are prefixed with 'a' (e.g., `arecv`).fixIf using `asyncio`, use `await sock.arecv()` and `await sock.asend()`. If explicitly using synchronous operations (less common in modern `pynng` code), ensure you are calling the non-`a` prefixed methods (`sock.recv()`, `sock.send()`). -
pynng.exceptions.NNGException: nng_dial failed: connection refused
cause The client attempted to connect to a server address, but no server was listening on that address and port, or a firewall is blocking the connection.fixEnsure your server process is running and actively listening on the specified address and port before the client attempts to dial. Check firewall rules if the server is on a different machine or network.
Warnings
- gotcha Pynng requires the nng C library. If it's not pre-installed on your system, `pip install pynng` will attempt to download and compile it from source. This requires a C compiler (e.g., GCC or Clang) and development headers to be available on your system.
- breaking Asyncio support was a major addition in pynng >= 0.8.0. Code written for older synchronous versions might need significant refactoring to take advantage of `asyncio` and `await`/`async` syntax (e.g., `sock.arecv()` instead of `sock.recv()`).
- gotcha Improper context management (introduced in 0.9.0) can lead to resource leaks or unexpected behavior, especially in complex applications or when dealing with multiple concurrency units.
Install
-
pip install pynng
Imports
- pynng
import nng
import pynng
- Rep0, Req0
from pynng import Rep0, Req0
Quickstart
import pynng
import asyncio
async def main():
addr = "tcp://127.0.0.1:5555"
async def server():
"""Simple Request-Reply server."""
with pynng.Rep0() as rep_sock:
rep_sock.listen(addr)
print("Server: Listening...")
# Receive and immediately reply, then close after 2 messages
for _ in range(2):
msg = await rep_sock.arecv()
print(f"Server: Received '{msg.decode()}'")
await rep_sock.asend(b"PONG")
print("Server: Done.")
async def client():
"""Simple Request-Reply client."""
await asyncio.sleep(0.1) # Give server a moment to start
with pynng.Req0() as req_sock:
req_sock.dial(addr)
print("Client: Dialed.")
for i in range(2):
await req_sock.asend(f"PING {i}".encode())
reply = await req_sock.arecv()
print(f"Client: Received '{reply.decode()}'")
print("Client: Done.")
await asyncio.gather(server(), client())
if __name__ == "__main__":
# This example demonstrates async usage, which is common in modern pynng applications.
asyncio.run(main())