我需要服务器向所有客户端发送消息(Python,套接字)

 巢i仔 发布于 2022-12-09 16:35

这是我的服务器程序,它如何将从每个客户端收到的数据发送给每个其他客户端?

import socket
import os
from threading import Thread
import thread

def listener(client, address):
    print "Accepted connection from: ", address

    while True:
        data = client.recv(1024)
        if not data:
            break
        else:
            print repr(data)
            client.send(data)

    client.close()

host = socket.gethostname()
port = 10016

s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((host,port))
s.listen(3)
th = []

while True:
    print "Server is listening for connections..."
    client, address = s.accept()
    th.append(Thread(target=listener, args = (client,address)).start())

s.close()

abarnert.. 10

如果需要向所有客户端发送消息,则需要以某种方式保留所有客户端的集合.例如:

clients = set()
clients_lock = threading.Lock()

def listener(client, address):
    print "Accepted connection from: ", address
    with clients_lock:
        clients.add(client)
    try:    
        while True:
            data = client.recv(1024)
            if not data:
                break
            else:
                print repr(data)
                with clients_lock:
                    for c in clients:
                        c.sendall(data)
    finally:
        with clients_lock:
            clients.remove(client)
            client.close()

将这部分内容分解为单独的函数可能会更加清晰,例如执行broadcast所有发送的函数.

无论如何,这是最简单的方法,但它有问题:

如果一个客户端的连接速度很慢,那么其他所有人都可能会陷入困境.虽然他们轮流阻止写入,但他们没有阅读任何东西,所以你可以溢出缓冲区并开始断开所有人的连接.

如果一个客户端有错误,其线程正在写入该客户端的客户端可能会获得异常,这意味着您将最终断开错误的用户.

因此,更好的解决方案是为每个客户端提供队列,并为读取器线程提供服务该队列的编写器线程.(然后你可以通过各种方式扩展它 - 对队列设置限制,以便人们不再试图与远远落后的人交谈,等等)


正如Anzel所指出的,除了每个客户端使用一个(或两个)线程之外,还有一种不同的设计服务器的方法:使用多路复用所有客户端事件的反应器.

Python 3.x有一些很好的内置库,但2.7只有笨重和过时asyncore/ asynchat低级别select.

正如Anzel所说,Python SocketServer:发送给多个客户端有一个答案asyncore,值得一读.但我实际上不会使用它.如果你想在Python 2.x中编写一个基于反应器的服务器,我要么使用更好的第三方框架,比如Twisted,要么找到或写一个直接位于其上的非常简单的框架select.

1 个回答
  • 如果需要向所有客户端发送消息,则需要以某种方式保留所有客户端的集合.例如:

    clients = set()
    clients_lock = threading.Lock()
    
    def listener(client, address):
        print "Accepted connection from: ", address
        with clients_lock:
            clients.add(client)
        try:    
            while True:
                data = client.recv(1024)
                if not data:
                    break
                else:
                    print repr(data)
                    with clients_lock:
                        for c in clients:
                            c.sendall(data)
        finally:
            with clients_lock:
                clients.remove(client)
                client.close()
    

    将这部分内容分解为单独的函数可能会更加清晰,例如执行broadcast所有发送的函数.

    无论如何,这是最简单的方法,但它有问题:

    如果一个客户端的连接速度很慢,那么其他所有人都可能会陷入困境.虽然他们轮流阻止写入,但他们没有阅读任何东西,所以你可以溢出缓冲区并开始断开所有人的连接.

    如果一个客户端有错误,其线程正在写入该客户端的客户端可能会获得异常,这意味着您将最终断开错误的用户.

    因此,更好的解决方案是为每个客户端提供队列,并为读取器线程提供服务该队列的编写器线程.(然后你可以通过各种方式扩展它 - 对队列设置限制,以便人们不再试图与远远落后的人交谈,等等)


    正如Anzel所指出的,除了每个客户端使用一个(或两个)线程之外,还有一种不同的设计服务器的方法:使用多路复用所有客户端事件的反应器.

    Python 3.x有一些很好的内置库,但2.7只有笨重和过时asyncore/ asynchat低级别select.

    正如Anzel所说,Python SocketServer:发送给多个客户端有一个答案asyncore,值得一读.但我实际上不会使用它.如果你想在Python 2.x中编写一个基于反应器的服务器,我要么使用更好的第三方框架,比如Twisted,要么找到或写一个直接位于其上的非常简单的框架select.

    2022-12-11 02:04 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有