Python SocketServer: sending to multiple clients?

后端 未结 4 533
太阳男子
太阳男子 2020-12-03 08:27

Well, I\'m trying to build a small python prgram with a SocketServer that is supposed to send messages it receives to all connected clients. I\'m stuck, I don\'t know how to

4条回答
  •  没有蜡笔的小新
    2020-12-03 09:12

    You want to look at asyncore here. The socket operations you're calling on the client side are blocking (don't return until some data is received or a timeout occurs) which makes it hard to listen for messages sent from the host and let the client instances enqueue data to send at the same time. asyncore is supposed to abstract the timeout-based polling loop away from you.

    Here's a code "sample" -- let me know if anything is unclear:

    from __future__ import print_function
    
    import asyncore
    import collections
    import logging
    import socket
    
    
    MAX_MESSAGE_LENGTH = 1024
    
    
    class RemoteClient(asyncore.dispatcher):
    
        """Wraps a remote client socket."""
    
        def __init__(self, host, socket, address):
            asyncore.dispatcher.__init__(self, socket)
            self.host = host
            self.outbox = collections.deque()
    
        def say(self, message):
            self.outbox.append(message)
    
        def handle_read(self):
            client_message = self.recv(MAX_MESSAGE_LENGTH)
            self.host.broadcast(client_message)
    
        def handle_write(self):
            if not self.outbox:
                return
            message = self.outbox.popleft()
            if len(message) > MAX_MESSAGE_LENGTH:
                raise ValueError('Message too long')
            self.send(message)
    
    
    class Host(asyncore.dispatcher):
    
        log = logging.getLogger('Host')
    
        def __init__(self, address=('localhost', 0)):
            asyncore.dispatcher.__init__(self)
            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
            self.bind(address)
            self.listen(1)
            self.remote_clients = []
    
        def handle_accept(self):
            socket, addr = self.accept() # For the remote client.
            self.log.info('Accepted client at %s', addr)
            self.remote_clients.append(RemoteClient(self, socket, addr))
    
        def handle_read(self):
            self.log.info('Received message: %s', self.read())
    
        def broadcast(self, message):
            self.log.info('Broadcasting message: %s', message)
            for remote_client in self.remote_clients:
                remote_client.say(message)
    
    
    class Client(asyncore.dispatcher):
    
        def __init__(self, host_address, name):
            asyncore.dispatcher.__init__(self)
            self.log = logging.getLogger('Client (%7s)' % name)
            self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
            self.name = name
            self.log.info('Connecting to host at %s', host_address)
            self.connect(host_address)
            self.outbox = collections.deque()
    
        def say(self, message):
            self.outbox.append(message)
            self.log.info('Enqueued message: %s', message)
    
        def handle_write(self):
            if not self.outbox:
                return
            message = self.outbox.popleft()
            if len(message) > MAX_MESSAGE_LENGTH:
                raise ValueError('Message too long')
            self.send(message)
    
        def handle_read(self):
            message = self.recv(MAX_MESSAGE_LENGTH)
            self.log.info('Received message: %s', message)
    
    
    if __name__ == '__main__':
        logging.basicConfig(level=logging.INFO)
        logging.info('Creating host')
        host = Host()
        logging.info('Creating clients')
        alice = Client(host.getsockname(), 'Alice')
        bob = Client(host.getsockname(), 'Bob')
        alice.say('Hello, everybody!')
        logging.info('Looping')
        asyncore.loop()
    

    Which results in the following output:

    INFO:root:Creating host
    INFO:root:Creating clients
    INFO:Client (  Alice):Connecting to host at ('127.0.0.1', 51117)
    INFO:Client (    Bob):Connecting to host at ('127.0.0.1', 51117)
    INFO:Client (  Alice):Enqueued message: Hello, everybody!
    INFO:root:Looping
    INFO:Host:Accepted client at ('127.0.0.1', 55628)
    INFO:Host:Accepted client at ('127.0.0.1', 55629)
    INFO:Host:Broadcasting message: Hello, everybody!
    INFO:Client (  Alice):Received message: Hello, everybody!
    INFO:Client (    Bob):Received message: Hello, everybody!
    

提交回复
热议问题