aiokcp


Nameaiokcp JSON
Version 0.0.4 PyPI version JSON
download
home_pageNone
SummaryKCP for asyncio and socketserver, based on kcp
upload_time2024-05-24 06:49:39
maintainerNone
docs_urlNone
authorryanrain2016
requires_python>=3.8
licenseNone
keywords asyncio kcp socket aio aiokcp
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # aiokcp
[kcp](https://github.com/skywind3000/kcp)的python实践, 提供了类似python中TCP相关的标准库相同的编程接口(asyncio, socket, socketserver),原tcp代码使用修改导入的方式可以轻松实现从tcp到kcp的平移替换。

## 什么是KCP?
KCP是一个致力于低延时的基于UDP自动重传的可靠传输协议。本身不包含任何网络传输的功能,使用回调的方式处理udp数据包的传输。详情见[kcp](https://github.com/skywind3000/kcp)

## 如何安装
`aiokcp`是基于cython绑定调用的kcp库,打包可能需要安装平台的编译工具。windows系统需要安装`vsbuilder`,linux系统需要安装`gcc`。安装完成后,可以通过`pip`安装
```bash
pip install aiokcp
```
如果需要数据包加密,可以选择安装`cryptography`
```bash
pip install aiokcp[crypto]
```

## 例子
例子详见`aiokcp/examples`目录
### asyncio 低级接口
这里实现了类似`loop.create_connection`和`loop.create_server`的功能
```py
import asyncio
import time

from aiokcp import create_connection, create_server


# copy from document of asyncio.Protocol
class EchoServerProtocol(asyncio.Protocol):
    def connection_made(self, transport):
        peername = transport.get_extra_info('peername')
        print('Connection from {}'.format(peername))
        self.transport = transport

    def data_received(self, data):
        message = data.decode()
        print('server: At {} Data received: {!r}'.format(time.time(), message))

        print('server: At {} Send: {!r}'.format(time.time(), message))
        self.transport.write(data)

        print('server: Close the client socket')
        self.transport.close()

# copy from document of asyncio.Protocol
class EchoClientProtocol(asyncio.Protocol):
    def __init__(self, message, on_con_lost):
        self.message = message
        self.on_con_lost = on_con_lost

    def connection_made(self, transport):
        transport.write(self.message.encode())
        print('client: At {} Data sent: {!r}'.format(time.time(), self.message))

    def data_received(self, data):
        print('client: At {} Data received: {!r}'.format(time.time(), data.decode()))

    def connection_lost(self, exc):
        print('client: The server closed the connection at {}'.format(time.time()))
        self.on_con_lost.set_result(True)

async def server():
    server = await create_server(EchoServerProtocol, '127.0.0.1', 8888,
        kcp_kwargs={ # optional
            # ...
        })
    async with server:
        await server.serve_forever()
    print('server done')

async def client():
    on_con_lost = asyncio.Future()
    transport, protocol = await create_connection(
        lambda: EchoClientProtocol('Hello World!', on_con_lost),
        '127.0.0.1', 8888,
        kcp_kwargs={   # optional
            # ...
        }
    )
    try:
        await on_con_lost
    finally:
        transport.close()

async def delay_client(delay = 1):
    await asyncio.sleep(delay)
    await client()

if __name__ == '__main__':
    async def main():
        await asyncio.gather(server(), client(), delay_client(1))

    asyncio.run(main())

```

### asyncio高级接口
```py
import asyncio
import time

from aiokcp import open_connection, start_server


async def handle_echo(reader, writer):
    n = 21000
    while n:
        data = await reader.read(100)
        n -= len(data)
        message = data.decode()
        addr = writer.get_extra_info('peername')

        print(f"server: At {time.time()} Received {message!r} from {addr!r}")

        print(f"server: At {time.time()} Send: {message!r}")
        writer.write(data)
        await writer.drain()
    print(f"server: At {time.time()} Close the connection")
    await asyncio.sleep(10)
    writer.close()
    await writer.wait_closed()
    print(f'server: At {time.time()} Done')

async def kcp_echo_client(message):
    reader, writer = await open_connection(
        '127.0.0.1', 8888, kcp_kwargs={
            # ...
        })

    print(f'client: At {time.time()} Send: {message!r}', len(message))
    writer.write(message.encode())
    await writer.drain()
    n = len(message)
    while n > 0:
        data = await reader.read(1000)
        print(f'client: At {time.time()} Received: {data.decode()!r}', len(data), n)
        n -= len(data)

    print(f'client: At {time.time()} Close the connection', '#' * 20)
    writer.close()
    await writer.wait_closed()

async def server():
    server = await start_server(
        handle_echo, '127.0.0.1', 8888, kcp_kwargs={
            # ...
        })
    async with server:
        await server.serve_forever()
    print('server done')

async def main():
    await asyncio.gather(server(), kcp_echo_client('Hello World!'))

if __name__ == '__main__':
    asyncio.run(main())
```

### 同步的kcp socketpair
```py
from aiokcp.sync import KCPSocket

sock1, sock2 = KCPSocket.socket_pair()
sock1.send(b'123')
print(sock2.recv(100))
sock2.send(b'234')
print(sock1.recv(100))
```
### 同步的kcp 简单服务器-客户端
```py
from aiokcp.sync import KCPSocket

sock1 = KCPSocket.create_server(('127.0.0.1', 18586))
sock2 = KCPSocket.create_connection(('127.0.0.1', 18586))
server_sock, _ = sock1.accept()
server_sock.send(b'123')
print(sock2.recv(100))
sock2.send(b'234')
print(server_sock.recv(100))
```

### 同步的kcp socketserver
```py
import os
import threading
import time

from aiokcp.sync import (BaseRequestHandler, KCPSocket, KCPThreadingServer,
                         StreamRequestHandler)


class Handler(BaseRequestHandler):
    def handle(self):
        nbytes = 0
        while True:
            # self.request is the KCP socket connected to the client
            data = self.request.recv(1024)
            print("Received from {}:{}".format(*self.client_address))
            # print("Data: {}".format(data))
            # just send back the same data
            # there is no mechanism to check if the connection is broken in kcp, but timeout.
            # when timeout occurs, the connection will be closed, recv will return empty bytes
            if not data:
                break
            nbytes += self.request.send(data)
            print('server recved: {} sent: {}'.format(nbytes, len(data)))
        print('server handle end ##################')

def server_thread(port):
    kw = {
        'kcp_kwargs': {
            # ...
        }
    }
    server = KCPThreadingServer(('127.0.0.1', port), Handler, **kw)
    thread = threading.Thread(target=server.serve_forever)
    thread.start()

def client_thread(port):
    kw = {
        'kcp_kwargs': {
            # ...
        }
    }
    sock = KCPSocket.create_connection(('127.0.0.1', port), **kw)
    sent_buf = b'abc'
    sock.send(sent_buf)
    for _ in range(1):
        b = os.urandom(7 * 1000)
        sent_buf += b
        sock.send(b)
    print('###########', len(sent_buf), '###########')
    n = len(sent_buf)
    buf = b''
    while n > 0:
        data = sock.recv(1024)
        buf += data
        if data:
            n -= len(data)
        else:
            break
        print('client recv', len(buf), len(data)) # print(buf, len(data))
        if buf[:7003-n] != sent_buf[:7003-n]:
            # ensure sent in order
            print('error')
            print(buf[:7003-n])
            print(sent_buf[:7003-n])
            break
    print('client handle end', '###############')

    time.sleep(1)
    sock.close()


if __name__ == '__main__':
    def thread_test():
        from random import randint
        port = randint(10000, 20000)
        server_thread(port)
        client_thread(port)

    thread_test()
```
### 同步的kcp socketserver 流处理
```py
import os
import threading
import time

from aiokcp.sync import (BaseRequestHandler, KCPSocket, KCPThreadingServer,
                         StreamRequestHandler)


class StreamHandler(StreamRequestHandler):
    def handle(self):
        print('handling')
        n = 0
        while True:
            # self.rfile is a file-like object created by the handler;
            # we can now use e.g. readline() instead of raw recv() calls
            data = self.rfile.readline().strip()
            if not data or data == 'end':
                break
            n += len(data)
            print('server recved: {} sent: {}'.format(n, len(data)))
            # Likewise, self.wfile is a file-like object used to write back
            # to the client
            self.wfile.write(data)
            self.wfile.flush()
        print('server handle end ##################')
        time.sleep(1)
        self.wfile.close()
        self.request.close()

def server_thread(port):
    kw = {
        'kcp_kwargs': {
            # ...
        },
        'stream': 1
    }
    server = KCPThreadingServer(('127.0.0.1', port), StreamHandler, **kw)
    thread = threading.Thread(target=server.serve_forever)
    thread.start()

def client_thread(port):
    kw = {
        'kcp_kwargs': {
            # ...
        },
        'stream': 1
    }
    sock = KCPSocket.create_connection(('127.0.0.1', port), **kw)
    sent_buf = b'abc\ndef\nghi\njkl\nmno\npqr\nstu\nvwx\nyza\nend\n'
    sock.send(sent_buf)
    buf = b''
    while len(buf) < 27:
        buf += sock.recv(27)
    print('client recv', buf)

if __name__ == '__main__':
    def thread_test():
        from random import randint
        port = randint(10000, 20000)
        server_thread(port)
        client_thread(port)

    thread_test()
```
### 可选的udp数据包加密
默认数据包不加密,但提供加密的方法和参数。内置的加密方法需要安装`cryptography`, 采用的aes+cbc模式加密+hmac校验。也可以自定义加密对象, 只需要实现`encrypt`和`decrypt`方法即可
```py
from aiokcp import (create_connection, create_server, open_connection,
                    start_server)
from aiokcp.crypto import get_crypto
from aiokcp.sync import KCPSocket

# need cryptography installed

key = b'12345678901234567890123456789012'
salt = b'1234567890123456'

crypto = get_crypto(key, salt)

# or

class Crypto:
    # need to implement encrypt and decrypt method
    def encrypt(self, data):
        pass

    def decrypt(self, data):
        pass

crypto = Crypto()

create_connection(..., crypto=crypto)

create_server(..., crypto=crypto)

open_connection(..., crypto=crypto)

start_server(..., crypto=crypto)


KCPSocket(..., crypto=crypto)

KCPSocket.create_connection(..., crypto=crypto)

KCPSocket.create_server(..., crypto=crypto)

KCPSocket.socket_pair(crypto=crypto)
```

### 相关配置
kcp默认配置如下,可以通过传递`kcp_kwargs`参数到相应的方法,改变相关配置,`kcp_kwargs`不用每个参数都设置,没有设置的使用默认值
```py
default_update_interval = 100  # ms

default_kcp_kwargs = {
    'max_transmission': 1400,
    'no_delay'        : True,
    'update_interval' : default_update_interval,
    'resend_count'     : 2,
    'no_congestion_control': False,
    'send_window_size': 32,
    'receive_window_size': 128,
    'stream': 0
}

default_timeout = 600
```
#### 相关配置修改
`KCPServer`, `KCPSteamTransport`, `sync.KCPServer`, `sync.KCPSocket`均提供下面的方法修改相关的配置
```py
def set_nodelay(self, no_delay: bool, update_interval: int, resend_count: int, no_congestion_control: bool):
    pass

def set_wndsize(self, send: int, receive: int):
    pass

def set_mtu(self, max_transmission: int):
    pass

def set_stream(self, stream: bool):
    pass
```

# 功能
- [x] asyncio低级接口: Protocol
- [x] asyncio高级接口: Stream
- [x] 同步的kcp socket的实现
- [x] 同步的kcp socketserver的实现
- [x] 可选的udp数据包加密
- [ ] close时通知对方关闭socket
- [ ] 支持tls/ssl

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "aiokcp",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "asyncio, kcp, socket, aio, aiokcp",
    "author": "ryanrain2016",
    "author_email": "ryanrain2016 <holidaylover2010@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/2c/16/0e0d03a4302569e3c6c917e441a2dcf6c3c155227d6c6fac6b509ea23e1a/aiokcp-0.0.4.tar.gz",
    "platform": null,
    "description": "# aiokcp\r\n[kcp](https://github.com/skywind3000/kcp)\u7684python\u5b9e\u8df5, \u63d0\u4f9b\u4e86\u7c7b\u4f3cpython\u4e2dTCP\u76f8\u5173\u7684\u6807\u51c6\u5e93\u76f8\u540c\u7684\u7f16\u7a0b\u63a5\u53e3(asyncio, socket, socketserver)\uff0c\u539ftcp\u4ee3\u7801\u4f7f\u7528\u4fee\u6539\u5bfc\u5165\u7684\u65b9\u5f0f\u53ef\u4ee5\u8f7b\u677e\u5b9e\u73b0\u4ecetcp\u5230kcp\u7684\u5e73\u79fb\u66ff\u6362\u3002\r\n\r\n## \u4ec0\u4e48\u662fKCP\uff1f\r\nKCP\u662f\u4e00\u4e2a\u81f4\u529b\u4e8e\u4f4e\u5ef6\u65f6\u7684\u57fa\u4e8eUDP\u81ea\u52a8\u91cd\u4f20\u7684\u53ef\u9760\u4f20\u8f93\u534f\u8bae\u3002\u672c\u8eab\u4e0d\u5305\u542b\u4efb\u4f55\u7f51\u7edc\u4f20\u8f93\u7684\u529f\u80fd\uff0c\u4f7f\u7528\u56de\u8c03\u7684\u65b9\u5f0f\u5904\u7406udp\u6570\u636e\u5305\u7684\u4f20\u8f93\u3002\u8be6\u60c5\u89c1[kcp](https://github.com/skywind3000/kcp)\r\n\r\n## \u5982\u4f55\u5b89\u88c5\r\n`aiokcp`\u662f\u57fa\u4e8ecython\u7ed1\u5b9a\u8c03\u7528\u7684kcp\u5e93\uff0c\u6253\u5305\u53ef\u80fd\u9700\u8981\u5b89\u88c5\u5e73\u53f0\u7684\u7f16\u8bd1\u5de5\u5177\u3002windows\u7cfb\u7edf\u9700\u8981\u5b89\u88c5`vsbuilder`\uff0clinux\u7cfb\u7edf\u9700\u8981\u5b89\u88c5`gcc`\u3002\u5b89\u88c5\u5b8c\u6210\u540e\uff0c\u53ef\u4ee5\u901a\u8fc7`pip`\u5b89\u88c5\r\n```bash\r\npip install aiokcp\r\n```\r\n\u5982\u679c\u9700\u8981\u6570\u636e\u5305\u52a0\u5bc6\uff0c\u53ef\u4ee5\u9009\u62e9\u5b89\u88c5`cryptography`\r\n```bash\r\npip install aiokcp[crypto]\r\n```\r\n\r\n## \u4f8b\u5b50\r\n\u4f8b\u5b50\u8be6\u89c1`aiokcp/examples`\u76ee\u5f55\r\n### asyncio \u4f4e\u7ea7\u63a5\u53e3\r\n\u8fd9\u91cc\u5b9e\u73b0\u4e86\u7c7b\u4f3c`loop.create_connection`\u548c`loop.create_server`\u7684\u529f\u80fd\r\n```py\r\nimport asyncio\r\nimport time\r\n\r\nfrom aiokcp import create_connection, create_server\r\n\r\n\r\n# copy from document of asyncio.Protocol\r\nclass EchoServerProtocol(asyncio.Protocol):\r\n    def connection_made(self, transport):\r\n        peername = transport.get_extra_info('peername')\r\n        print('Connection from {}'.format(peername))\r\n        self.transport = transport\r\n\r\n    def data_received(self, data):\r\n        message = data.decode()\r\n        print('server: At {} Data received: {!r}'.format(time.time(), message))\r\n\r\n        print('server: At {} Send: {!r}'.format(time.time(), message))\r\n        self.transport.write(data)\r\n\r\n        print('server: Close the client socket')\r\n        self.transport.close()\r\n\r\n# copy from document of asyncio.Protocol\r\nclass EchoClientProtocol(asyncio.Protocol):\r\n    def __init__(self, message, on_con_lost):\r\n        self.message = message\r\n        self.on_con_lost = on_con_lost\r\n\r\n    def connection_made(self, transport):\r\n        transport.write(self.message.encode())\r\n        print('client: At {} Data sent: {!r}'.format(time.time(), self.message))\r\n\r\n    def data_received(self, data):\r\n        print('client: At {} Data received: {!r}'.format(time.time(), data.decode()))\r\n\r\n    def connection_lost(self, exc):\r\n        print('client: The server closed the connection at {}'.format(time.time()))\r\n        self.on_con_lost.set_result(True)\r\n\r\nasync def server():\r\n    server = await create_server(EchoServerProtocol, '127.0.0.1', 8888,\r\n        kcp_kwargs={ # optional\r\n            # ...\r\n        })\r\n    async with server:\r\n        await server.serve_forever()\r\n    print('server done')\r\n\r\nasync def client():\r\n    on_con_lost = asyncio.Future()\r\n    transport, protocol = await create_connection(\r\n        lambda: EchoClientProtocol('Hello World!', on_con_lost),\r\n        '127.0.0.1', 8888,\r\n        kcp_kwargs={   # optional\r\n            # ...\r\n        }\r\n    )\r\n    try:\r\n        await on_con_lost\r\n    finally:\r\n        transport.close()\r\n\r\nasync def delay_client(delay = 1):\r\n    await asyncio.sleep(delay)\r\n    await client()\r\n\r\nif __name__ == '__main__':\r\n    async def main():\r\n        await asyncio.gather(server(), client(), delay_client(1))\r\n\r\n    asyncio.run(main())\r\n\r\n```\r\n\r\n### asyncio\u9ad8\u7ea7\u63a5\u53e3\r\n```py\r\nimport asyncio\r\nimport time\r\n\r\nfrom aiokcp import open_connection, start_server\r\n\r\n\r\nasync def handle_echo(reader, writer):\r\n    n = 21000\r\n    while n:\r\n        data = await reader.read(100)\r\n        n -= len(data)\r\n        message = data.decode()\r\n        addr = writer.get_extra_info('peername')\r\n\r\n        print(f\"server: At {time.time()} Received {message!r} from {addr!r}\")\r\n\r\n        print(f\"server: At {time.time()} Send: {message!r}\")\r\n        writer.write(data)\r\n        await writer.drain()\r\n    print(f\"server: At {time.time()} Close the connection\")\r\n    await asyncio.sleep(10)\r\n    writer.close()\r\n    await writer.wait_closed()\r\n    print(f'server: At {time.time()} Done')\r\n\r\nasync def kcp_echo_client(message):\r\n    reader, writer = await open_connection(\r\n        '127.0.0.1', 8888, kcp_kwargs={\r\n            # ...\r\n        })\r\n\r\n    print(f'client: At {time.time()} Send: {message!r}', len(message))\r\n    writer.write(message.encode())\r\n    await writer.drain()\r\n    n = len(message)\r\n    while n > 0:\r\n        data = await reader.read(1000)\r\n        print(f'client: At {time.time()} Received: {data.decode()!r}', len(data), n)\r\n        n -= len(data)\r\n\r\n    print(f'client: At {time.time()} Close the connection', '#' * 20)\r\n    writer.close()\r\n    await writer.wait_closed()\r\n\r\nasync def server():\r\n    server = await start_server(\r\n        handle_echo, '127.0.0.1', 8888, kcp_kwargs={\r\n            # ...\r\n        })\r\n    async with server:\r\n        await server.serve_forever()\r\n    print('server done')\r\n\r\nasync def main():\r\n    await asyncio.gather(server(), kcp_echo_client('Hello World!'))\r\n\r\nif __name__ == '__main__':\r\n    asyncio.run(main())\r\n```\r\n\r\n### \u540c\u6b65\u7684kcp socketpair\r\n```py\r\nfrom aiokcp.sync import KCPSocket\r\n\r\nsock1, sock2 = KCPSocket.socket_pair()\r\nsock1.send(b'123')\r\nprint(sock2.recv(100))\r\nsock2.send(b'234')\r\nprint(sock1.recv(100))\r\n```\r\n### \u540c\u6b65\u7684kcp \u7b80\u5355\u670d\u52a1\u5668-\u5ba2\u6237\u7aef\r\n```py\r\nfrom aiokcp.sync import KCPSocket\r\n\r\nsock1 = KCPSocket.create_server(('127.0.0.1', 18586))\r\nsock2 = KCPSocket.create_connection(('127.0.0.1', 18586))\r\nserver_sock, _ = sock1.accept()\r\nserver_sock.send(b'123')\r\nprint(sock2.recv(100))\r\nsock2.send(b'234')\r\nprint(server_sock.recv(100))\r\n```\r\n\r\n### \u540c\u6b65\u7684kcp socketserver\r\n```py\r\nimport os\r\nimport threading\r\nimport time\r\n\r\nfrom aiokcp.sync import (BaseRequestHandler, KCPSocket, KCPThreadingServer,\r\n                         StreamRequestHandler)\r\n\r\n\r\nclass Handler(BaseRequestHandler):\r\n    def handle(self):\r\n        nbytes = 0\r\n        while True:\r\n            # self.request is the KCP socket connected to the client\r\n            data = self.request.recv(1024)\r\n            print(\"Received from {}:{}\".format(*self.client_address))\r\n            # print(\"Data: {}\".format(data))\r\n            # just send back the same data\r\n            # there is no mechanism to check if the connection is broken in kcp, but timeout.\r\n            # when timeout occurs, the connection will be closed, recv will return empty bytes\r\n            if not data:\r\n                break\r\n            nbytes += self.request.send(data)\r\n            print('server recved: {} sent: {}'.format(nbytes, len(data)))\r\n        print('server handle end ##################')\r\n\r\ndef server_thread(port):\r\n    kw = {\r\n        'kcp_kwargs': {\r\n            # ...\r\n        }\r\n    }\r\n    server = KCPThreadingServer(('127.0.0.1', port), Handler, **kw)\r\n    thread = threading.Thread(target=server.serve_forever)\r\n    thread.start()\r\n\r\ndef client_thread(port):\r\n    kw = {\r\n        'kcp_kwargs': {\r\n            # ...\r\n        }\r\n    }\r\n    sock = KCPSocket.create_connection(('127.0.0.1', port), **kw)\r\n    sent_buf = b'abc'\r\n    sock.send(sent_buf)\r\n    for _ in range(1):\r\n        b = os.urandom(7 * 1000)\r\n        sent_buf += b\r\n        sock.send(b)\r\n    print('###########', len(sent_buf), '###########')\r\n    n = len(sent_buf)\r\n    buf = b''\r\n    while n > 0:\r\n        data = sock.recv(1024)\r\n        buf += data\r\n        if data:\r\n            n -= len(data)\r\n        else:\r\n            break\r\n        print('client recv', len(buf), len(data)) # print(buf, len(data))\r\n        if buf[:7003-n] != sent_buf[:7003-n]:\r\n            # ensure sent in order\r\n            print('error')\r\n            print(buf[:7003-n])\r\n            print(sent_buf[:7003-n])\r\n            break\r\n    print('client handle end', '###############')\r\n\r\n    time.sleep(1)\r\n    sock.close()\r\n\r\n\r\nif __name__ == '__main__':\r\n    def thread_test():\r\n        from random import randint\r\n        port = randint(10000, 20000)\r\n        server_thread(port)\r\n        client_thread(port)\r\n\r\n    thread_test()\r\n```\r\n### \u540c\u6b65\u7684kcp socketserver \u6d41\u5904\u7406\r\n```py\r\nimport os\r\nimport threading\r\nimport time\r\n\r\nfrom aiokcp.sync import (BaseRequestHandler, KCPSocket, KCPThreadingServer,\r\n                         StreamRequestHandler)\r\n\r\n\r\nclass StreamHandler(StreamRequestHandler):\r\n    def handle(self):\r\n        print('handling')\r\n        n = 0\r\n        while True:\r\n            # self.rfile is a file-like object created by the handler;\r\n            # we can now use e.g. readline() instead of raw recv() calls\r\n            data = self.rfile.readline().strip()\r\n            if not data or data == 'end':\r\n                break\r\n            n += len(data)\r\n            print('server recved: {} sent: {}'.format(n, len(data)))\r\n            # Likewise, self.wfile is a file-like object used to write back\r\n            # to the client\r\n            self.wfile.write(data)\r\n            self.wfile.flush()\r\n        print('server handle end ##################')\r\n        time.sleep(1)\r\n        self.wfile.close()\r\n        self.request.close()\r\n\r\ndef server_thread(port):\r\n    kw = {\r\n        'kcp_kwargs': {\r\n            # ...\r\n        },\r\n        'stream': 1\r\n    }\r\n    server = KCPThreadingServer(('127.0.0.1', port), StreamHandler, **kw)\r\n    thread = threading.Thread(target=server.serve_forever)\r\n    thread.start()\r\n\r\ndef client_thread(port):\r\n    kw = {\r\n        'kcp_kwargs': {\r\n            # ...\r\n        },\r\n        'stream': 1\r\n    }\r\n    sock = KCPSocket.create_connection(('127.0.0.1', port), **kw)\r\n    sent_buf = b'abc\\ndef\\nghi\\njkl\\nmno\\npqr\\nstu\\nvwx\\nyza\\nend\\n'\r\n    sock.send(sent_buf)\r\n    buf = b''\r\n    while len(buf) < 27:\r\n        buf += sock.recv(27)\r\n    print('client recv', buf)\r\n\r\nif __name__ == '__main__':\r\n    def thread_test():\r\n        from random import randint\r\n        port = randint(10000, 20000)\r\n        server_thread(port)\r\n        client_thread(port)\r\n\r\n    thread_test()\r\n```\r\n### \u53ef\u9009\u7684udp\u6570\u636e\u5305\u52a0\u5bc6\r\n\u9ed8\u8ba4\u6570\u636e\u5305\u4e0d\u52a0\u5bc6\uff0c\u4f46\u63d0\u4f9b\u52a0\u5bc6\u7684\u65b9\u6cd5\u548c\u53c2\u6570\u3002\u5185\u7f6e\u7684\u52a0\u5bc6\u65b9\u6cd5\u9700\u8981\u5b89\u88c5`cryptography`, \u91c7\u7528\u7684aes+cbc\u6a21\u5f0f\u52a0\u5bc6+hmac\u6821\u9a8c\u3002\u4e5f\u53ef\u4ee5\u81ea\u5b9a\u4e49\u52a0\u5bc6\u5bf9\u8c61, \u53ea\u9700\u8981\u5b9e\u73b0`encrypt`\u548c`decrypt`\u65b9\u6cd5\u5373\u53ef\r\n```py\r\nfrom aiokcp import (create_connection, create_server, open_connection,\r\n                    start_server)\r\nfrom aiokcp.crypto import get_crypto\r\nfrom aiokcp.sync import KCPSocket\r\n\r\n# need cryptography installed\r\n\r\nkey = b'12345678901234567890123456789012'\r\nsalt = b'1234567890123456'\r\n\r\ncrypto = get_crypto(key, salt)\r\n\r\n# or\r\n\r\nclass Crypto:\r\n    # need to implement encrypt and decrypt method\r\n    def encrypt(self, data):\r\n        pass\r\n\r\n    def decrypt(self, data):\r\n        pass\r\n\r\ncrypto = Crypto()\r\n\r\ncreate_connection(..., crypto=crypto)\r\n\r\ncreate_server(..., crypto=crypto)\r\n\r\nopen_connection(..., crypto=crypto)\r\n\r\nstart_server(..., crypto=crypto)\r\n\r\n\r\nKCPSocket(..., crypto=crypto)\r\n\r\nKCPSocket.create_connection(..., crypto=crypto)\r\n\r\nKCPSocket.create_server(..., crypto=crypto)\r\n\r\nKCPSocket.socket_pair(crypto=crypto)\r\n```\r\n\r\n### \u76f8\u5173\u914d\u7f6e\r\nkcp\u9ed8\u8ba4\u914d\u7f6e\u5982\u4e0b\uff0c\u53ef\u4ee5\u901a\u8fc7\u4f20\u9012`kcp_kwargs`\u53c2\u6570\u5230\u76f8\u5e94\u7684\u65b9\u6cd5\uff0c\u6539\u53d8\u76f8\u5173\u914d\u7f6e\uff0c`kcp_kwargs`\u4e0d\u7528\u6bcf\u4e2a\u53c2\u6570\u90fd\u8bbe\u7f6e\uff0c\u6ca1\u6709\u8bbe\u7f6e\u7684\u4f7f\u7528\u9ed8\u8ba4\u503c\r\n```py\r\ndefault_update_interval = 100  # ms\r\n\r\ndefault_kcp_kwargs = {\r\n    'max_transmission': 1400,\r\n    'no_delay'        : True,\r\n    'update_interval' : default_update_interval,\r\n    'resend_count'     : 2,\r\n    'no_congestion_control': False,\r\n    'send_window_size': 32,\r\n    'receive_window_size': 128,\r\n    'stream': 0\r\n}\r\n\r\ndefault_timeout = 600\r\n```\r\n#### \u76f8\u5173\u914d\u7f6e\u4fee\u6539\r\n`KCPServer`, `KCPSteamTransport`, `sync.KCPServer`, `sync.KCPSocket`\u5747\u63d0\u4f9b\u4e0b\u9762\u7684\u65b9\u6cd5\u4fee\u6539\u76f8\u5173\u7684\u914d\u7f6e\r\n```py\r\ndef set_nodelay(self, no_delay: bool, update_interval: int, resend_count: int, no_congestion_control: bool):\r\n    pass\r\n\r\ndef set_wndsize(self, send: int, receive: int):\r\n    pass\r\n\r\ndef set_mtu(self, max_transmission: int):\r\n    pass\r\n\r\ndef set_stream(self, stream: bool):\r\n    pass\r\n```\r\n\r\n# \u529f\u80fd\r\n- [x] asyncio\u4f4e\u7ea7\u63a5\u53e3: Protocol\r\n- [x] asyncio\u9ad8\u7ea7\u63a5\u53e3: Stream\r\n- [x] \u540c\u6b65\u7684kcp socket\u7684\u5b9e\u73b0\r\n- [x] \u540c\u6b65\u7684kcp socketserver\u7684\u5b9e\u73b0\r\n- [x] \u53ef\u9009\u7684udp\u6570\u636e\u5305\u52a0\u5bc6\r\n- [ ] close\u65f6\u901a\u77e5\u5bf9\u65b9\u5173\u95edsocket\r\n- [ ] \u652f\u6301tls/ssl\r\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "KCP for asyncio and socketserver, based on kcp",
    "version": "0.0.4",
    "project_urls": {
        "Homepage": "https://github.com/ryanrain2016/aiokcp",
        "Issues": "https://github.com/ryanrain2016/aiokcp/issues"
    },
    "split_keywords": [
        "asyncio",
        " kcp",
        " socket",
        " aio",
        " aiokcp"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e691ea8aec253eaf86fdd92086d83de12fba31a1399cbc5ae8f952ed0a38d7a0",
                "md5": "41032ea6ec86dc622d96d87a629fb580",
                "sha256": "4b3fa0aa67c7589637bd8432165cee087e9e3478af1bf7ee2fd64832d47778ce"
            },
            "downloads": -1,
            "filename": "aiokcp-0.0.4-cp310-cp310-win_amd64.whl",
            "has_sig": false,
            "md5_digest": "41032ea6ec86dc622d96d87a629fb580",
            "packagetype": "bdist_wheel",
            "python_version": "cp310",
            "requires_python": ">=3.8",
            "size": 176629,
            "upload_time": "2024-05-24T06:49:37",
            "upload_time_iso_8601": "2024-05-24T06:49:37.873758Z",
            "url": "https://files.pythonhosted.org/packages/e6/91/ea8aec253eaf86fdd92086d83de12fba31a1399cbc5ae8f952ed0a38d7a0/aiokcp-0.0.4-cp310-cp310-win_amd64.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2c160e0d03a4302569e3c6c917e441a2dcf6c3c155227d6c6fac6b509ea23e1a",
                "md5": "3e1c4a6c8cbc87963a179429636e6311",
                "sha256": "e1f8455d8e87bd711e993cead22191896336f8be1bd37212f515a26146bf152e"
            },
            "downloads": -1,
            "filename": "aiokcp-0.0.4.tar.gz",
            "has_sig": false,
            "md5_digest": "3e1c4a6c8cbc87963a179429636e6311",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 123239,
            "upload_time": "2024-05-24T06:49:39",
            "upload_time_iso_8601": "2024-05-24T06:49:39.736980Z",
            "url": "https://files.pythonhosted.org/packages/2c/16/0e0d03a4302569e3c6c917e441a2dcf6c3c155227d6c6fac6b509ea23e1a/aiokcp-0.0.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-05-24 06:49:39",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ryanrain2016",
    "github_project": "aiokcp",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "aiokcp"
}
        
Elapsed time: 2.54428s