python 如何从服务器向客户端发送按需数据

pn9klfpd  于 2023-09-29  发布在  Python
关注(0)|答案(1)|浏览(138)

我使用asyncio实现了一个TCP服务器,它以固定的间隔从客户端接收数据,比如每30秒一次。现在,我的目标是按需向客户端发送数据。为了实现这一点,我打算建立一种机制,在其中可以在客户端设置特定的参数。因此,我需要为此目的从服务器向客户端发送消息。
我曾尝试实施这一点,但它是行不通的
这是我的代码

import asyncio
from protocol import Message  # Import your Message class from protocol.py

class TCPServer:

    def __init__(self, host, port):
        self.host = host
        self.port = port
        self.server = None
        self.clients = {}  # Dictionary to store connected clients
        self.input_queue = asyncio.Queue()  # Queue for console input

    async def handle_client(self, reader, writer):
       message = Message()  # Create an instance of your Message class
       addr = writer.get_extra_info('peername')

       # Convert the client address to a string for consistency
       client_address = f"{addr[0]}:{addr[1]}"

       try:
           self.clients[client_address] = writer  # Store the writer for this client

           while True:
               data = await reader.read(1024)
               if not data:
                   break

               # Assuming your Message class has a `raw_data` method
               response = message.raw_data(data)

               print(f"Received {data!r} from {addr!r}")

               print(f"Send: {response!r}")
               writer.write(response.encode())
               await writer.drain()

    except ConnectionResetError as e:
        print(f"ConnectionResetError: {e}")
    except Exception as e:
        print(f"Error: {e}")
    finally:
        print(f"Client {addr!r} closed the connection")
        writer.close()
        await writer.wait_closed()
        del self.clients[client_address]  # Remove the client from the list when they 
       disconnect

    async def send_to_client(self, client_address, message):
          if client_address in self.clients:
             writer = self.clients[client_address]
             writer.write(message.encode())
             await writer.drain()
         else:
             print("Client not found or not connected.")

   async def start(self):
        self.server = await asyncio.start_server(
        self.handle_client, self.host, self.port)

        addr = self.server.sockets[0].getsockname()
        print(f'Serving on {addr}')

        async with self.server:
            await self.server.serve_forever()

  async def stop(self):
        if self.server:
           self.server.close()
           await self.server.wait_closed()
           print("Server stopped")

  async def console_input(self):
       while True:
           client_address = await self.input_queue.get()
           hex_data = input("Enter the hex data to send: ")
           try:
               byte_data = bytes.fromhex(hex_data)
               await self.send_to_client(client_address, byte_data)
          except ValueError:
               print("Invalid hex data format.")

 if __name__ == '__main__':
     host = '127.0.0.1'  # Change this to the desired host
     port = 8888  # Change this to the desired port

     server = TCPServer(host, port)

    async def main():
        try:
          server_task = asyncio.create_task(server.start())
          console_task = asyncio.create_task(server.console_input())

          # Add client address to the input queue for testing
          await asyncio.sleep(2)  # Wait for the server to start (adjust as needed)
          client_address = '127.0.0.1:8888'
          server.input_queue.put_nowait(client_address)

          await asyncio.gather(server_task, console_task)
      except KeyboardInterrupt:
          print("KeyboardInterrupt: Server shutting down...")
          await server.stop()

  asyncio.run(main())
6rqinv9w

6rqinv9w1#

看起来你想在Python中使用asyncio实现一个TCP服务器,它可以定期从客户端接收数据,并按需向客户端发送数据。但是,你提到发送部分不工作。为了帮助您解决这个问题,我将为您的代码提供一些指导和潜在的修复:
确保正确的消息处理:
在send_to_client方法中,使用writer.write(message.encode())向客户端发送数据。但是,您需要考虑客户端期望如何接收和处理此数据。确保客户端知道如何解析和处理服务器发送的消息。正确处理队列任务:
在main函数中,为server.start()和server.console_input()创建任务。但是,您应该使用awaitasyncio.gather(...)等待这些任务,以确保它们并发运行。下面是代码的修改版本,其中包含以下更改:

import asyncio
from protocol import Message  # Import your Message class from protocol.py

class TCPServer:

    def __init__(self, host, port):
        self.host = host
        self.port = port
        self.server = None
        self.clients = {}  # Dictionary to store connected clients
        self.input_queue = asyncio.Queue()  # Queue for console input

    async def handle_client(self, reader, writer):
        message = Message()  # Create an instance of your Message class
        addr = writer.get_extra_info('peername')

        # Convert the client address to a string for consistency
        client_address = f"{addr[0]}:{addr[1]}"

        try:
            self.clients[client_address] = writer  # Store the writer for this client

            while True:
                data = await reader.read(1024)
                if not data:
                    break

                # Assuming your Message class has a `raw_data` method
                response = message.raw_data(data)

                print(f"Received {data!r} from {addr!r}")

                print(f"Send: {response!r}")
                writer.write(response.encode())
                await writer.drain()

        except ConnectionResetError as e:
            print(f"ConnectionResetError: {e}")
        except Exception as e:
            print(f"Error: {e}")
        finally:
            print(f"Client {addr!r} closed the connection")
            writer.close()
            await writer.wait_closed()
            del self.clients[client_address]  # Remove the client from the list when they disconnect

    async def send_to_client(self, client_address, message):
        if client_address in self.clients:
            writer = self.clients[client_address]
            writer.write(message.encode())
            await writer.drain()
        else:
            print("Client not found or not connected.")

    async def start(self):
        self.server = await asyncio.start_server(
            self.handle_client, self.host, self.port)

        addr = self.server.sockets[0].getsockname()
        print(f'Serving on {addr}')

        async with self.server:
            await self.server.serve_forever()

    async def stop(self):
        if self.server:
            self.server.close()
            await self.server.wait_closed()
            print("Server stopped")

    async def console_input(self):
        while True:
            client_address = await self.input_queue.get()
            hex_data = input("Enter the hex data to send: ")
            try:
                byte_data = bytes.fromhex(hex_data)
                await self.send_to_client(client_address, byte_data)
            except ValueError:
                print("Invalid hex data format.")

if __name__ == '__main__':
    host = '127.0.0.1'  # Change this to the desired host
    port = 8888  # Change this to the desired port

    server = TCPServer(host, port)

    async def main():
        try:
            server_task = asyncio.create_task(server.start())
            console_task = asyncio.create_task(server.console_input())

            # Add client address to the input queue for testing
            await asyncio.sleep(2)  # Wait for the server to start (adjust as needed)
            client_address = '127.0.0.1:8888'
            server.input_queue.put_nowait(client_address)

            await asyncio.gather(server_task, console_task)
        except KeyboardInterrupt:
            print("KeyboardInterrupt: Server shutting down...")
            await server.stop()

    asyncio.run(main())

请注意,我已经删除了向客户端发送消息时的.encode()方法,假设您的消息已经是字节格式。确保客户端也需要相同格式的数据。此外,请确保正确实现了protocol.py文件,以处理服务器发送的消息。

相关问题