TCP framework in flavor of Netty
Project description
py-netty :rocket:
An epoll-based event-driven TCP networking framework.
Ideas and concepts under the hood are build upon those of Netty, especially the IO and executor model.
APIs are intuitive to use if you are a Netty alcoholic.
Installation
pip install py-netty
Getting Started
Start an echo server:
from py_netty import ServerBootstrap
ServerBootstrap().bind(address='0.0.0.0', port=8080).close_future().sync()
Start an echo server (TLS):
from py_netty import ServerBootstrap
ServerBootstrap(certfile='/path/to/cert/file', keyfile='/path/to/cert/file').bind(address='0.0.0.0', port=9443).close_future().sync()
As TCP client:
from py_netty import Bootstrap, ChannelHandlerAdapter
class HttpHandler(ChannelHandlerAdapter):
def channel_read(self, ctx, buffer):
print(buffer.decode('utf-8'))
remote_address, remote_port = 'www.google.com', 80
b = Bootstrap(handler_initializer=HttpHandler)
channel = b.connect(remote_address, remote_port).sync().channel()
request = f'GET / HTTP/1.1\r\nHost: {remote_address}\r\n\r\n'
channel.write(request.encode('utf-8'))
input() # pause
channel.close()
As TCP client (TLS):
from py_netty import Bootstrap, ChannelHandlerAdapter
class HttpHandler(ChannelHandlerAdapter):
def channel_read(self, ctx, buffer):
print(buffer.decode('utf-8'))
remote_address, remote_port = 'www.google.com', 443
b = Bootstrap(handler_initializer=HttpHandler, tls=True, verify=True)
channel = b.connect(remote_address, remote_port).sync().channel()
request = f'GET / HTTP/1.1\r\nHost: {remote_address}\r\n\r\n'
channel.write(request.encode('utf-8'))
input() # pause
channel.close()
TCP port forwarding:
from py_netty import ServerBootstrap, Bootstrap, ChannelHandlerAdapter, EventLoopGroup
class ProxyChannelHandler(ChannelHandlerAdapter):
def __init__(self, remote_host, remote_port, client_eventloop_group):
self._remote_host = remote_host
self._remote_port = remote_port
self._client_eventloop_group = client_eventloop_group
self._client = None
def _client_channel(self, ctx0):
class __ChannelHandler(ChannelHandlerAdapter):
def channel_read(self, ctx, bytebuf):
ctx0.write(bytebuf)
def channel_inactive(self, ctx):
ctx0.close()
if self._client is None:
self._client = Bootstrap(
eventloop_group=self._client_eventloop_group,
handler_initializer=__ChannelHandler
).connect(self._remote_host, self._remote_port).sync().channel()
return self._client
def exception_caught(self, ctx, exception):
ctx.close()
def channel_read(self, ctx, bytebuf):
self._client_channel(ctx).write(bytebuf)
def channel_inactive(self, ctx):
if self._client:
self._client.close()
proxied_server, proxied_port = 'www.google.com', 443
client_eventloop_group = EventLoopGroup(2, 'ClientEventloopGroup')
sb = ServerBootstrap(
parant_group=EventLoopGroup(1, 'Acceptor'),
child_group=EventLoopGroup(2, 'Worker'),
child_handler_initializer=lambda: ProxyChannelHandler(proxied_server, proxied_port, client_eventloop_group)
)
sb.bind(port=8443).close_future().sync()
Event-driven callbacks
Create handler with callbacks for interested events:
from py_netty import ChannelHandlerAdapter
class MyChannelHandler(ChannelHandlerAdapter):
def channel_active(self, ctx: 'ChannelHandlerContext') -> None:
# invoked when channel is active (TCP connection ready)
pass
def channel_read(self, ctx: 'ChannelHandlerContext', msg: Union[bytes, socket.socket]) -> None:
# invoked when there is data ready to process
pass
def channel_inactive(self, ctx: 'ChannelHandlerContext') -> None:
# invoked when channel is inactive (TCP connection is broken)
pass
def channel_registered(self, ctx: 'ChannelHandlerContext') -> None:
# invoked when the channel is registered with a eventloop
pass
def channel_unregistered(self, ctx: 'ChannelHandlerContext') -> None:
# invoked when the channel is unregistered from a eventloop
pass
def channel_handshake_complete(self, ctx: 'ChannelHandlerContext') -> None:
# invoked when ssl handshake is complete, this only applies to client side
pass
def exception_caught(self, ctx: 'ChannelHandlerContext', exception: Exception) -> None:
# invoked when there is any exception raised during process
pass
Performance Test
This is a rough performance test. Echo server is implemented using py-netty/python socket (blocking mode)/java netty. RTT is measured for payload 32B/1024B.
Caveats
- No pipeline, supports only one handler FOR NOW
- No batteries-included codecs FOR NOW
- No pool or refcnt for bytes buffer, bytes objects are created and consumed at your disposal
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
py-netty-0.0.21.tar.gz
(14.9 kB
view hashes)
Built Distribution
py_netty-0.0.21-py3-none-any.whl
(15.4 kB
view hashes)
Close
Hashes for py_netty-0.0.21-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c502c573326f7bfe0117b37228c494e5dbc8f0195015c1322b77e8c40c0d90fd |
|
MD5 | ae2f289a0dc602364353b640e1637aa4 |
|
BLAKE2b-256 | eba920adbaa8f4a3f8e4cded88a36abd0b97ed016b7538292a1ff2fa2e5aa1b1 |