套接字与线程间通信

1 投票
2 回答
2289 浏览
提问于 2025-04-16 19:45

我正在使用多线程的TCP服务器。每个客户端的连接都是通过单独的线程来处理的。我想通过socket的send()方法向所有客户端发送数据。但我遇到的问题是,这个方法只会把数据发送给当前线程(也就是接收到数据的那个线程)。

我找不到关于Python中线程间通信的好文档。

有没有什么解决办法,让我可以向所有客户端发送数据呢?

谢谢。

    #!/usr/bin/env python

    """
    A server with multithreading to handle multiple clients.
    """

    import select
    import socket
    import sys
    import threading
    import logging
    import datetime

    class Server:
        def __init__(self):
            self.host = ''
            self.port = 25000
            self.backlog = 5
            self.size = 1024
            self.server = None

        def open_socket(self):
            try:
                self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.server.bind((self.host,self.port))
                self.server.listen(5)
                lc.append(self.server)
            except socket.error, (value,message):
                if self.server:
                    self.server.close()
                print "Could not open socket: " + message
                sys.exit(1)

        def run(self):
            self.open_socket()
            input = [self.server,sys.stdin]
            running = 1
            while running:
                inputready,outputready,exceptready = select.select(input,[],[])

                for s in inputready:
                    if s == self.server:
                        c = Client(self.server.accept())
                        c.start()
                        threads.append(c)

            # close all threads
            self.server.close()
            for c in threads:
                c.join()

    class Client(threading.Thread):
        def __init__(self,(client,address)):
            threading.Thread.__init__(self)
            self.client = client
            self.address = address
            self.size = 1024
            dc[address[0]]=client#address[1]
            logging.info('%s added successfully...',address[0])


        def run(self):
            running = 1
            print dc
            while running:
                data = str(self.client.recv(self.size))
                #print dc

                if data.strip() == '0x01':
                    sendtoAll()
                elif data.strip() == '0x02':
                    self.client.send("version"+data)
                elif data.strip() == '0x03':#return current time
                    print datetime.datetime.now()
                    self.client.send(str(datetime.datetime.now()))
                else:
                    self.client.send("empty")
                    #self.client.close()
                    #running = 0
def sendtoAll():
        for i, sock in dc.items():
            print "Address:Sockets = ", i,sock
            try:
                print "sending to %s by Thread "%i
                sock.send("data"+str(threading.current_thread().getName()))
            except socket.error,e:
                print "error socket %s\n" % e
                sock.close()
                del lc[i]

if __name__ == "__main__":
        dc={}       #dict to store ip-address:scokets pair
        lc=[]       #tuples to store all sockets
        threads=[]  #holds threads
        logging.basicConfig(level=logging.INFO)
        logging.info('Starting Server Object...')
        s = Server()
        s.run()

客户端代码是

import socket
import sys

host = '192.168.1.4'
port = 25000
size = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host,port))
sys.stdout.write('%')

while 1:
    # read from keyboard
    line = sys.stdin.readline()
    if line == '\n':
        break
    s.send(line)
    data = s.recv(size)
    sys.stdout.write(data)
    sys.stdout.write('\n%')
s.close()

2 个回答

1

你可以把你的线程变成对象(如果有的话),让它们变得可以“迭代”,然后你可以写一个“广播”函数,这个函数会遍历你的线程,利用它们的套接字来发送信息。

如果你没有每个线程对应一个对象,你也可以简单地用一个套接字的列表,做差不多的事情。

确保根据你的需求正确使用锁(可以是对所有套接字使用锁,或者是对每个单独的套接字使用锁)。

0

TCP套接字是两个端点之一。在TCP中没有“广播”这个概念。如果你想把一条消息发送给所有的客户端,你必须一个一个地发送给他们。

如果你为所有的客户端对象使用一个合适的容器,那么你只需要遍历这个容器,把消息发送给每一个客户端就可以了。

撰写回答