Python / Socket:如何在不等待响应的情况下发送多条消息?

时间:2017-12-07 08:42:01

标签: python sockets

我想使用套接字模块发送多条消息,而无需等待客户端或服务器的响应。但是,下面的代码不能这样做。为了做到这一点,你有什么建议?提前谢谢。

以下是代码:

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

1 个答案:

答案 0 :(得分:1)

好的,所以对于你想要实现的目标,你需要完全改变方法并使用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 documentation。 其他可能的方法涉及使用线程或多处理。我不会说他们比asyncio容易。