使用 asyncio 的 Python 简单套接字客户端/服务器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/48506460/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 18:44:02  来源:igfitidea点击:

Python simple socket client/server using asyncio

pythonsocketspython-asyncio

提问by srjjio

I would like to re-implement my code using asyncio coroutines instead of multi-threading.

我想使用 asyncio 协程而不是多线程重新实现我的代码。

server.py

服务器.py

def handle_client(client):
    request = None
    while request != 'quit':
        request = client.recv(255).decode('utf8')
        response = cmd.run(request)
        client.send(response.encode('utf8'))
    client.close()

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('localhost', 15555))
server.listen(8)

try:
    while True:
        client, _ = server.accept()
        threading.Thread(target=handle_client, args=(client,)).start()
except KeyboardInterrupt:
    server.close()

client.py

客户端.py

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.connect(('localhost', 15555))
request = None

try:
    while request != 'quit':
        request = input('>> ')
        if request:
            server.send(request.encode('utf8'))
            response = server.recv(255).decode('utf8')
            print(response)
except KeyboardInterrupt:
    server.close()

I know there are some appropriate asynchronous network librairies to do that. But I just want to only use asyncio core library on this case in order to have a better understanding of it.

我知道有一些合适的异步网络库可以做到这一点。但我只想在这种情况下只使用 asyncio 核心库,以便更好地理解它。

It would have been so nice to only add async keyword before handle client definition... Here a piece of code which seems to work, but I'm still confused about the implementation.

在处理客户端定义之前只添加 async 关键字会非常好......这是一段似乎有效的代码,但我仍然对实现感到困惑。

asyncio_server.py

asyncio_server.py

def handle_client(client):
    request = None
    while request != 'quit':
        request = client.recv(255).decode('utf8')
        response = cmd.run(request)
        client.send(response.encode('utf8'))
    client.close()

def run_server(server):
    client, _ = server.accept()
    handle_client(client)

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('localhost', 15555))
server.listen(8)

loop = asyncio.get_event_loop()
asyncio.async(run_server(server))
try:
    loop.run_forever()
except KeyboardInterrupt:
    server.close()

How adapt this in the best way and using async await keywords.

如何以最佳方式适应这一点并使用 async await 关键字。

回答by user4815162342

The closest literal translation of the threading code would create the socket as before, make it non-blocking, and use asynciolow-level socket operationsto implement the server. Here is an example, sticking to the more relevant server part (the client is single-threaded and likely fine as-is):

线程代码最接近的字面翻译将像以前一样创建套接字,使其非阻塞,并使用asyncio低级套接字操作来实现服务器。这是一个例子,坚持更相关的服务器部分(客户端是单线程的,可能按原样运行):

import asyncio, socket

async def handle_client(client):
    request = None
    while request != 'quit':
        request = (await loop.sock_recv(client, 255)).decode('utf8')
        response = str(eval(request)) + '\n'
        await loop.sock_sendall(client, response.encode('utf8'))
    client.close()

async def run_server():
    while True:
        client, _ = await loop.sock_accept(server)
        loop.create_task(handle_client(client))

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('localhost', 15555))
server.listen(8)
server.setblocking(False)

loop = asyncio.get_event_loop()
loop.run_until_complete(run_server())

The above works, but is not the intended way to use asyncio. While the correct abstraction will depend on the application, you probably want to at least utilize asyncio.start_serverand not work with raw sockets. This significantly reduces the line count of code:

上述工作,但不是预期的使用方式asyncio。虽然正确的抽象取决于应用程序,但您可能至少希望使用asyncio.start_server原始套接字而不是使用原始套接字。这显着减少了代码的行数:

async def handle_client(reader, writer):
    request = None
    while request != 'quit':
        request = (await reader.read(255)).decode('utf8')
        response = str(eval(request)) + '\n'
        writer.write(response.encode('utf8'))
        await writer.drain()
    writer.close()

loop = asyncio.get_event_loop()
loop.create_task(asyncio.start_server(handle_client, 'localhost', 15555))
loop.run_forever()

See the documentationfor details.

有关详细信息,请参阅文档