当前位置: 首页 > 面试题库 >

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

白越
2023-03-14
问题内容

我想使用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()

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

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()

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

仅在处理客户端定义之前添加async关键字真是太好了……这里的一段代码似乎有效,但是我仍然对实现感到困惑。

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()

如何以最佳方式和使用异步await关键字来对此进行调整。


问题答案:

与线程代码最接近的文字翻译将像以前一样创建套接字,使其成为非阻塞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())

以上方法有效,但不是预期的使用方式asyncio。这是非常低级的,因此容易出错,需要您记住在鞋e上设置适当的标志。另外,由于没有缓冲,因此从插座读取线之类的简单操作就变得繁琐。这个API级别实际上只是用于替代事件循环实现者,这将提供
他们的 执行sock_recvsock_sendall等等。

虽然正确的抽象将取决于应用程序,但是您可能至少要利用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()

有关详细信息,请参见文档。



 类似资料:
  • 问题内容: 我正在构建一个小型聊天应用程序,其中客户端A希望通过服务器B将某些东西发送到客户端C。首先,这是解决问题的正确方法吗?我能够向服务器发送数据或从服务器接收数据,但仅限于客户端。例如,如果客户端A向服务器B发送数据而客户端C向服务器B发送数据,则我可以将数据发送回服务器A和C就像回显服务器一样。但是我想要的是将来自客户端A的数据通过服务器B转发到客户端C。 以下是服务器代码: 客户端代码

  • 我试图用java实现一个客户端服务器,在这里我读取客户端中的输入并在服务器中执行UperCase,然后返回客户端并打印UperCase。我使用ObjectOutputStream和ObjectInputStream进行读写,但是当我在客户机中键入一个msg时,程序会显示以下错误: Digite uma msg casa java.io.eofexception位于java.io.datainput

  • 问题内容: 我已经阅读了很多有关该主题的内容,telnet是一种协议,而不是简单的套接字连接,正在等待换行符,使用外部库等等。 最重要的是,我需要启动并运行一个快速且肮脏的Java telnet应用程序,它不一定可扩展且不一定漂亮,因此我试图避免使用库,系统函数调用等。我一直在尝试和测试,到目前为止,当尝试登录路由器(当然是通过telnet)时,我什么都没有。 这是到目前为止我一直在使用的代码的一

  • 我是 python 和套接字的新手,正在尝试编写一个回显客户端/服务器套接字。我已经编写了服务器,以便丢失 30% 的数据包。我将客户端编程为在一秒后超时,因为数据包可能会丢失。但是,每当我运行客户端套接字时,我的输出都是 100% 请求超时。我假设我得到这个输出,因为我的服务器从未收到过消息。我已经多次查看了我的代码,但无法弄清楚为什么我不断获得此输出。下面是我的服务器和客户端套接字的代码。任何

  • 我对套接字有点陌生,我正在尝试编写一个程序,在这个程序中,我基本上可以从客户端程序向服务器程序发送一些简单的请求。现在我只想在客户端有1或2个选项供用户选择。例如,如果用户在客户端选择“选项1”,那么服务器会返回一条消息“您选择选项1”,以此类推,但我不知道如何读取服务器上从客户端发送的输入。 客户代码: 服务器代码: 我需要在Clinet中使用两个不同的BufferedReader吗?一个用于用

  • 正在编写一个服务器,使用Java套接字的客户端聊天程序。这是我的服务器套接字类的代码。 客户端能够建立连接并向服务器发送消息。服务器也可以接收客户端发送的消息。问题是当消息从服务器发送时,客户端没有收到消息。这是我的客户端套接字代码。