Skip to main content

Asyncio UDP server

Build Status

Yet another async UDP server. Based on bare sockets.

Killer-feature: bandwidth throttling for uploading & downloading.

UDPServer.__init__

UDP server constructor.

Arguments:

  • upload_speed — maximum outgoing traffic speed in "byter per second" (default: 0 — unlimited);
  • download_speed — maximum incoming traffic speed in "byter per second" (default: 0 — unlimited);
  • recv_max_size — maximum socket window size for receiving (default: 262144).

UDPServer.run

Server startup function.

Arguments:

  • host — socket bind host/interface (e.g. "0.0.0.0", "127.0.0.1" or "localhost");
  • port — socket listen port;
  • loop — event loop.

UDPServer.send

Enqueue data for sending.

Arguments:

  • databytes or bytearray data for sending;
  • addr — tuple of host and port (e.g. ("127.0.0.1", 9876) or ("some.domain.com", 5556)).

UDPServer.subscribe

Subscribe coro or future on a datagram received event.

Arguments:

  • fut — coroutine or future with arguments data and addr.

UDPServer.unsubscribe

Unsubscribe coro or future from a datagram received event.

Arguments:

  • fut — coroutine or future.

Virtual events

  • UDPServer._connection_made() — virtual method, call after socket bind successfully;
  • UDPServer._socket_error(data, addr) — virtual method, call when got socket error;
  • UDPServer._datagram_received(data, addr) — virtual method, call each time when server got incoming data, can be used for modify data before pass it to subscribers;
  • UDPServer._notify_subscribers(data, addr) — virtual method, call with params returned from _datagram_received.

Example

import asyncio
import datetime

from aioudp import UDPServer


class MyUDPServer:
    def __init__(self, server, loop):
        self.server = server
        self.loop = loop
        # Subscribe for incoming udp packet event
        self.server.subscribe(self.on_datagram_received)
        asyncio.ensure_future(self.do_send(), loop=self.loop)

    async def on_datagram_received(self, data, addr):
        # Override virtual method and process incoming data
        print(datetime.datetime.now(), addr, data)

    async def do_send(self):
        while True:
            # Any payload
            payload = b'd1:ad2:id20:k\xe7\x90\xcd\x0c_R\xfe\x82\xeb\xa8 x\x14\xb4-\x8e0\xe5\x086:target20:\x11\x8e\xcc,\x89\xa4\x99\xf98E\x98\x7f!\xa7w\rz\x1b\x14de1:q9:find_node1:t2:#K1:y1:qe'
            # Delay for prevent tasks concurency
            await asyncio.sleep(0.001)
            # Enqueue data for send
            self.server.send(payload, ("router.bittorrent.com", 6881))

async def main(loop):
    # Bandwidth speed is 100 bytes per second
    udp = UDPServer(download_speed=100, upload_speed=100)
    udp.run("0.0.0.0", 12346, loop=loop)

    server = MyUDPServer(server=udp, loop=loop)
   

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main(loop))
    loop.run_forever()

Output:

2019-06-04 16:04:07.761576 ('67.215.246.10', 6881) b'd2:ip6:Z\x97\'X0:1:rd2:id20:2\xf5NisQ\xffJ\xec)\xcd\xba\xab\xf2\xfb\xe3F|\xc2g5:nodes416:\x02\xf7\xb7\x1d\x94\xb1\x00\xe8\x84\xca\x9c\xc3\xb09\xbb\x04*P\x8cQ\x1f\x7fF\xa9\x1a\xe1\x00\x13\x99W\x14\xb1\x99\x8b\xff\x8e\xda2\xb3 \xac\x82\xef0sCl\xda+G\xc4\x91\x17bO,\xe8\xbc\x9e\xeb+\xfc.\xe6\xf8\xb0\x82\xee~\x17 \xebvF\x83\xf8\x83\xc1\xdaK\x1b\x83\x17\xfb!\xab\x1e\x97T\xa3\xfa\x9a\x14Q$\x06)\\\xad>O\x03\xc4\x91\x9f/7\xf6>]|\xe0\xc6f\x1eq\xfd\xcc\x0e\xbe\xd0\x85\xde\xf9\xbeJc\xe3e\xe5\x9e\x9d\xca})P\xa5\xfd\x8c\xb66\xb9\xba\x0f\xfc\xb1\xb9\xa3 E\xc9*\x1f\xd1I\xb1r9\xfaI\xf1\xf1\xbb\xe9\xeb\xb3\xa6\xdb<\x87\x0c>\x99$^R\xbc\x85\xd3\xb3C\xab}\xbf6\xcc\x11\x7fv\xde\r\xed\xa4q\xdd\x04#\x8d\xd8j7$[\xe5e\\\xf9V\x166\xb1P\x7f\xa01v\xf49\xb9\x9a\x12*\xad<Q@\xa6\x8d\xd5\xe6wN\xa2\x87\xaf|\xb4KslP\xf5\xd0h\xaf\x1c\xb5\xb6\xc0\xc9\xfa\x0c\xfe\xe8\xb92\n\xb7\xda"8\x019\x95\xe8\xef\xc1u\xa4$\xe5\x0c!\xe2\x10j\xff\x10\xeb\xffu\x02\x87t\x9f\x01|\xa4b\x87\xc4\xa0.\xd2g\x9f\xf6\xd1\xc2\xfd\xef\xa1!a\x04\xdf<\x97)\xbe\xd1\x81l\xb1?W\t\xbb\xc1\xbd\x04\x8ec\xf8\x08\xcd\x1av\x1a\xa9\xb3R^\xb5{\x11\x1a\xe1C\xe1\xb43\x04\x03Wl\xd1E\xa6\x0f\xf7\xcbQ\t\x84W\xd6\xebD\'\xdd=\xb1\xc9\xed\xc6C\xf9\x7f\xfbg\xf9$\x0e\x0b~\xa5\xae\xfdnvr\xe7\xc4.\xf8(\x90\xa4\x84C\xe9\xccK4r\xc6=\xf1\xc09\xdf{\xfc\x10\xe9\xd9\xd8\xa5\xdd.\x00\x88\x0e\xe7]e1:t2:#K1:y1:re'
2019-06-04 16:04:12.622861 ('67.215.246.10', 6881) b'd2:ip6:Z\x97\'X0:1:rd2:id20:2\xf5NisQ\xffJ\xec)\xcd\xba\xab\xf2\xfb\xe3F|\xc2g5:nodes416:\x1e\xe4\xb8\x96\xf5E;\x13\r\x89\n\x1c\xdb\xae2 \x9aP\xee\xcb\xa0\xb0\xcbq\xa4X\x80\x8c>\x91:M\xb67%kY\xc7\xb5\xe1\xe7\x901_u\\\xbd(g\xeb[\xa7-\x1fl\x1e\xd6\x93\xe8g\xdam\n;\xa8y \xf4K\x18\xe0\x11z\xfe\xa6\xf6\xc9\xcfe\xcb\xf9\x7f+"92\xfb/\xd8C>K\x1a\xf9\xe8#\x86\x8dy\x07\xa1\x94>\x81\x17_\xcd\xe9\x03?\x96pX\x1c\xe8v{\xa5W,_ \x0f|Oi\x8bg\xc5J\xfd#\x9e\xf7\xdd\xc4\xa4\xb9\xd0\x8f\xbd\x9d\x98\xfaD\x91N}U{j\xd7\xfak\')\xcdr(\xc3\xdc\xc6\xd7\x9b=\x1d\x12/\xa4\xd5A\x8f[\x98\x07\x10EHq#\xcc\xb8\xae\xf00\xd4\xfd(\xe5fj\xbb\xdd\xa5s\x8b\xec:\xb1\x1d\x93%)S\xdf.\xb3\x17\x95\x9b\xc8\xc0\x95"\x86\x81\x16\x8d]\xdau\x15S\xbcN:\x9d\x83I+Vk\xc4\x91\x0b9t\xbdv`\xb2\x8d7\xae\t\xb1\x8c\x96\x9f\x1c\xa0B\xd0\x93\xbfd\x8e\xe7\xdf`\x14\x13\'<\x92Pn:u\xa0\n\xc3\xcd\x01\x12H\xc65\xeb\xa2X\xc8\xd6\x0b\x81\x1b\xcf\x89\xbco$\x8a\xf97\x920u\xb8i\xde\x15\x19\xc4\x8f\xfb\xc0\xb1\xcf\x99\xd9e1\xf6u\x01\xb7\x1e\xc4\x80\xca\x0e\xcawuv\xc9\xaf[\x0b\xd4\x99\xf4[\xf1\x8ck\x1a\xe1r\xc3\xb4(\xb8ba\x98\x8b\x1e\xb4TN"\xa7F5B\xcb\x0f\x05\x9e\xed-b\x82\xb8\x8d\xed\xf7\xaf?,\xc5)z\xd2f\xc1\xda`.\xf0.!\xf2H\xbezs\xf3\x8c\t\x9c\x9d\xe8\x87Q\xf4\xe9\x8fJ\x0c\x16\xa8\xc55Q\x878<\x04.0Bc!\xade1:t2:#K1:y1:re'
2019-06-04 16:04:17.483860 ('67.215.246.10', 6881) b'd2:ip6:Z\x97\'X0:1:rd2:id20:2\xf5NisQ\xffJ\xec)\xcd\xba\xab\xf2\xfb\xe3F|\xc2g5:nodes416:k*[\x0c1\x9a\xb1\xd6\xe5>G\x0c\xac\xe3v0\xd0\xc2\xb7\x8cI\x93\xb7\xcd\xa8\xf1\xca(\xf8\xc0\xe0\xa6\xd4\xda*\xd4\xf1\xedc\xb4\xdf\xdf\xe2Q\x1a\xe9^\t\x8f\xfa\x1a\xe1$Wr\xe18\x1e\x9a\xce\xabW}\xbfLY\x05\xbd\xce\xa0\x0e\xb1_\x19\xdf>\xcaJS\x00H\xdf\x8d\xeedn\xd7\x07-\x9f\x8at\xb0\x14\xbe\x8d\x1d\x0eO\xa7\x97\xa3\x83\xa9\xb2\xff\xc9K\x97\x01m\xbc\xcb\xc3\x001vR\'s\xffyr\x82UF\\z\xafG\x8f\xc8U\xcf}+\x97\x90\xa2\x1b\x11\xef\xbfs\x80Q\xff\x1dc\x14%\xe8\x87\xac!\xadz\xbd\xcc\xbfq\xaex0\x7f(}jY[W\xdcsx\n|F\x86\xed\xa3\x1a\xe1,\x03\x87to\xd2X\x12\x00\x90\t\xcfu\xec_m\x15\x02\xe1\xf6\xd4\x98\x93\xfa\x1a\xe1\xc8\xa1-tC!\xd1X\xb0\xc9M\xc8\xf2\x94|\xca\x80j\xb8\x04\x05\xceB"_\xc3H\xf1i\x86\xb6\x07Z=\xc2\xb1`m\xab\xbc\xbeB\xb8\nVM]Q\x1cp\xc2L\x83\xca\xe7\xed\x1e\x10\x9d\xc9\xde\xdc[c\xef\xc2_]+N\xaaJ\xc9E0\xf5\x1b\x16q\xe1/\x97w>a\x94\x10\x0f\x94\xc2"\xd6\x89+\xa7\x01\\w%\x90Z_\x1a\xe1\xd9\xf5\xff\xb5D\xf2\x8d\xbc^[j\x16\xb9H\xe3.+\r\x87\xa5aU\xafMT\xec\x80\x02\x9bP\xf5\xc7\xe9\x8e\x9e\x94\x96\xc8\xcdu\xa1\xc1.\xa7 \xb5I\x0b\x9d\xef\xd0\x8ff\x91+\xc2\xe0\xeb/\xbe\x05\x87\xac\xd8\xb8vA\xe8?V\xa3\xfdJ\xc1\x9f\xe8\xc4\x91=\xc4\x16H\xbdP\x1fv5x9\x02\'N]Zh\xed\xc9\xc3\xb5\xae:\x04\xc8\x04e1:t2:#K1:y1:re'
2019-06-04 16:04:22.345648 ('67.215.246.10', 6881) b'd2:ip6:Z\x97\'X0:1:rd2:id20:2\xf5NisQ\xffJ\xec)\xcd\xba\xab\xf2\xfb\xe3F|\xc2g5:nodes416:+S\xdc\x8c\xc8%~ \x12\xd3\xd9@\xa9X4\x9at\xcc\x8a\xf9z\x08\x1d\x16h/\xf2}\xb7I\xd9\x8fP\x81(\x9d\xed\xae\xa5\xe5\xe4S1,\xf0-\xaeavL\xc4\x91~\xd5\x01`o\xa8\xc4\xe0\xfa \xa5\xf0\xf1~`\x0c\x19[+\x85\xbb\xd0\x0bp\xf3\x8c\xe98S\xcd`=n|\xa8\x8c\xa4~\xfc\xedg\xce\xff\x8f\x13}g\xfc\xc9)\xa8\x89L&]\\\xb3M\xc6NUE\x7f\xb8CQ\x82\xe1{C\xba\xaf\x884g\x9a\xf3\x8c\x1a\xe0\xbb\x1a\x12\xafCQ\x1e\x18\x91;\x80P\xee\xf0\xdc\t\xc1m.\xe4\x04\xda1\xff\x93?\xa0r\xc5\x1d\x9c\x1f\xc7\xf2\x0e[\xc9\tV4\x94\x02w\xc2\\b\x03+\x1a\xe1\xc4\x80#z0\x14\x9d}Kj\xbe\xf2>\xa5\xf8k\x12\x9a|u\xb0:\xc1,U\r\xc7kE\xa1UY\x1e~:r\x14\xb6p&\xd7\xdf\xaf>\x9b\xa5b\xb5\xcd\x1f\xc4\x91Z\xdf\x1a\x1f\xdb\x9a\x84\tu\xff\xda(\xddqy}nT\xaa\x8f%\x06.\xc9\xda\xe4\xc0\x9a\x03\x9c\x12?\xf1s[\xb1\xd7;\xe3)\xb9[o\r\xb6=\xb57\x98&\xc4\x91.\xd1\x87)5\xf5s\xb8\xc9z\xc4\x9d\x063Kw\xaf\xcc\x046\xdbN\xcf,\xf3\x8c\xaa\x85\xee\xd0e\xfa\xca\xd2\x93\x82\xe2\x98\xeaA\xdc\xbd\xaf\x97F\xe9r\x19\xb4i\xde~>\x82\xfb\xe9y#vJ\xe4\x8e\x0e\xd1\xee]\xe0qk(\xb2\x92\x95\xff\x02\n\x98\x9c"\xcaY\x8d\xb6\x81a\xa1\xf9\xc1\nX\xb4\x9e\xcfo\xbf\xa3j\x8fH1\'7\xc4\x91v\xd1_\xec\xe4\xe1\x1f\xcb\xd5\xbd\xf43\x0c\'"\x04\xa5\xa2\x0f\xd0\x05>+\xb1 Xe1:t2:#K1:y1:re'

Release files for aio-udp-server 0.0.7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aio-udp-server 0.0.7
File Size Uploaded
aio-udp-server-0.0.7.tar.gz 18.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for aio-udp-server 0.0.7
File Interpreter ABI Platform
aio_udp_server-0.0.7-py3-none-any.whl Python 3 none any Details

Total release size: 38.1 kB

Release files / aio-udp-server-0.0.7.tar.gz

Download URL aio-udp-server-0.0.7.tar.gz
Size 18.9 kB
Tags Source
SHA-256 checksum
How to use checksums
e69bf1bca4bf40a46fc19d2a856106faf20309a83424d6fb162ac47cb2c4f674
BLAKE2b-256 checksum
How to use checksums
43fdaab21755dbd0f7f15435beda77ff388a68e27ec9e87b88e5467f57a7094b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.1 importlib_metadata/4.6.1 pkginfo/1.7.1 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.2 CPython/3.9.6

Release files / aio_udp_server-0.0.7-py3-none-any.whl

Download URL aio_udp_server-0.0.7-py3-none-any.whl
Size 19.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b4aadd76814347b4801e47798bdaae2c2d680cc21ae40cd6d86c33ed2999055a
BLAKE2b-256 checksum
How to use checksums
f3c1e7aa5cab2fcb3d532270c3b4e1b0aceea3fdda1bb5971cd34e623f75f3ea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.1 importlib_metadata/4.6.1 pkginfo/1.7.1 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.2 CPython/3.9.6

Release history Release notifications | RSS feed

This release

0.0.7 This release

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page