Python中的多客户端服务器 - 如何广播?

时间:2017-04-20 07:49:04

标签: python sockets

我在线使用线程在线发现了一个简单的多客户端echo服务器:

#!/usr/bin/env python
import socket
import sys
import threading

class Client(threading.Thread):
    def __init__(self, ip, port, connection):
        threading.Thread.__init__(self)
        self.connection = connection
        self.ip = ip
        self.port = port

    def run(self):

        data = self.connection.recv(1024)
        if data :
            self.connection.sendall(data)
        else :
            self.connection.close()

class Server:
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port
        self.address = (self.ip, self.port)
        self.server = None
        self.clients = []

    def open_socket(self):
        try:
            self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server.bind(self.address)
        except socket.error, e:
            if self.server:
                self.server.close()
            sys.exit(1)

    def run(self):
        self.open_socket()
        self.server.listen(5)

        while True :
            connection, (ip, port) = self.server.accept()

            c = Client(ip, port, connection)
            c.start()

            self.clients.append(c)

        self.server.close()

if __name__ == '__main__':
    s = Server('127.0.0.1', 6666)
    s.run()

我写了一个客户:

import socket
import sys

port = 6666
size = 1024
s = None
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    host = socket.gethostname()
    s.connect(('127.0.0.1', port))
except socket.error, (value, message):
    if s:
        s.close()
    print "Could not open socket: " + message
    sys.exit(1)
data = raw_input('> ')
s.sendall(data)
data = s.recv(size)
print "Server sent: %s " % data
s.close()

一切都很好,但我想知道如何将广播功能添加到服务器以便能够将消息回显给所有连接的客户端?或者能够向特定客户发送消息?

我在服务器类中拥有所有客户端,但我不知道如何(以及服务器代码中的哪个位置,在Client类或Server类中广播和发送私信的代码?谢谢。

修改

新服务器:

#!/usr/bin/env python
import socket
import sys
import threading

class Client(threading.Thread):
    def __init__(self, ip, port, connection):
        threading.Thread.__init__(self)
        self.connection = connection
        self.ip = ip
        self.port = port

    def run(self):
        while True:
            data = self.connection.recv(1024)
            if data :
                self.connection.sendall(data)
            else :
                break
        self.connection.close()


class Server:
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port
        self.address = (self.ip, self.port)
        self.server = None
        self.clients = []

    def send_to_all_clients(self, msg):
        for client in self.clients :
            client.connection.send(msg)

    def send_to_client(self, ip, port, msg):
        for client in self.clients :
            if client.ip == ip and client.port == port :
                client.connection.send(msg)

    def open_socket(self):
        try:
            self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server.bind(self.address)
        except socket.error, e:
            if self.server:
                self.server.close()
            sys.exit(1)

    def run(self):
        self.open_socket()
        self.server.listen(5)

        while True :
            connection, (ip, port) = self.server.accept()

            c = Client(ip, port, connection)
            c.start()

            self.clients.append(c)

        self.server.close()

if __name__ == '__main__':
    s = Server('127.0.0.1', 6666)
    s.run()

新客户:

import socket
import sys

port = 6666
size = 1024
s = None
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    host = socket.gethostname()
    s.connect(('127.0.0.1', port))
except socket.error, (value, message):
    if s:
        s.close()
    print "Could not open socket: " + message
    sys.exit(1)

while True:
    data = raw_input('> ')
    s.sendall(data)
    data = s.recv(size)
    print "Server sent: %s " % data
s.close()

1 个答案:

答案 0 :(得分:3)

由于您已在Server中拥有客户列表,因此您可以在以下功能中使用它:

def send_to_all_clients(self, msg):  
    for client in self.clients : 
        client.connection.send(msg)

然后您可以创建一个选择特定客户端的功能:

def send_to_client(self, ip, port, msg): 
    for client in self.clients :  
        if client.ip == ip and client.port == port :  
            client.connection.send(msg)

注意
最好向Send()添加Client方法并将其调用以发送msg,而不是使用client.connection.send(msg)

如果您修改它以处理事件,则可以在服务器的run方法中使用这些函数 (您可以使用select.select()或用户输入(KeyboardInterrupt)等来实现,设计由您决定。)
另外,您应该同时修改client.py和Client,并使其更具持久性,因为现在close sendallrecv时就会admin_token.base64。 我希望这会给你一些想法