Python/套接字:如何在不等待响应的情况下发送多消息



我想使用套接字模块发送多消息,而无需等待客户端或服务器的响应。但是,下面的代码无法做到这一点。您的建议是什么?预先感谢。

这是代码:

server.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("", 12345))
s.listen(1)
print(s)
c, addr = s.accept()
print('{} connected.'.format(addr))
while True:
    respond = input("Server: ").encode("utf-8")
    if respond == b"q":
        exit()
    else:
        c.sendall(bytes(respond))
        data = str(c.recv(1024))[1:]
        if data:
            print("Client: {}".format(data))

client.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("", 12345))
while True:
    respond = input("Client: ").encode("utf-8")
    if respond == b"q":
        exit()
    else:
        s.sendall(bytes(respond))
        data = str(s.recv(1024))[1:]
        if data:
            print("Server: {}".format(data))

好吧,因此,对于要实现的目标,您需要完全更改该方法并使用套接字方法的asyncio等效物,并替换裸露的标准输入处理。

以下代码可在 python> = 3.5 上使用,并且需要aioconsole Python软件包,可以使用pip install aioconsole安装。

server.py

import asyncio
import aioconsole

class StreamWrapper(object):
    """This class is used to make socket stream created by server available for send_messgaes() function"""
    def __init__(self):
        self.reader = None
        self.writer = None
async def send_messages(stream_wrapper, stdin):
    # Wait asynchronously until server part initializes socket stream
    while stream_wrapper.writer is None:
        await asyncio.sleep(0.1)
    writer = stream_wrapper.writer
    # Asynchronusly read from standard input
    async for message in stdin:
        if message.decode().strip() == "q":
            writer.close()
            exit()
        else:
            # Send message through the socket
            writer.write(message)

def receive_messages_wrapper(stream_wrapper, stdout):
    """Wrapper function which adds stream_wrapper and stdout to the scope of receive_messages()"""
    async def receive_messages(reader, writer):
        # Copy socket stream reference to stream wrapper
        stream_wrapper.reader = reader
        stream_wrapper.writer = writer
        # Asynchronusly read messages from the socket
        async for message in reader:
            stdout.write('nClient: {}'.format(message.decode()))
            stdout.write("Server: ")
    # Wrapper returns receive_messages function with enhanced scope - receive_messages() can "see" stream_wrapper and stdout
    return receive_messages
async def run_server(loop):
    """Initialize stdin and stdout asynchronous streams and start the server"""
    stdin, stdout = await aioconsole.get_standard_streams()
    stream_wrapper = StreamWrapper()
    # Asynchronously execute send_messages and start_server()
    await asyncio.gather(
        send_messages(stream_wrapper, stdin),
        asyncio.start_server(receive_messages_wrapper(stream_wrapper, stdout), '127.0.0.1', 8888, loop=loop)
    )
# Run the server on the event loop
loop = asyncio.get_event_loop()
loop.run_until_complete(run_server(loop))
loop.close()

client.py

import asyncio
import aioconsole
async def send_messages(writer, stdin):
    # Asynchronusly read from standard input
    async for message in stdin:
        if message.decode().strip() == "q":
            writer.close()
            exit()
        else:
            # Send message through the socket
            writer.write(message)
async def receive_messages(reader, stdout):
    # Asynchronusly read messages from the socket
    async for message in reader:
        stdout.write('nServer: {}'.format(message.decode()))
        stdout.write("Client: ")
async def run_client(loop):
    """Initialize stdin and stdout asynchronous streams and open the client connection, then start exchanging messages"""
    stdin, stdout = await aioconsole.get_standard_streams()
    reader, writer = await asyncio.open_connection('127.0.0.1', 8888)
    stdout.write("Client: ")
    # Asynchronously execute send_messages and receive_messages()
    await asyncio.gather(
        send_messages(writer, stdin),
        receive_messages(reader, stdout)
    )
# Run the client on the event loop
loop = asyncio.get_event_loop()
loop.run_until_complete(run_client(loop))
loop.close()

,如果您以前从未使用过asyncio,这似乎很复杂,但它确实可以做您想要的。您可以从任何端(客户端或服务器)垃圾邮件多个消息,而另一端将在等待用户输入时接收并打印。我已经提供了评论,但是如果您想充分理解它,则应该熟悉异步文档。其他可能的方法涉及使用线程或多处理。我不会说它们比asyncio容易。

最新更新