简体   繁体   English

如何用python socketserver.TCPServer制作多客户端聊天室

[英]How to make a multi-client chat room with python socketserver.TCPServer

I have to make a multi-client chat room with TCPServer provided by serversocket module in Python. How do i make this into a multi-client server and send the message to all other client?我必须使用 Python 中的 serversocket 模块提供的 TCPServer 创建一个多客户端聊天室。我如何将变成一个多客户端服务器并将消息发送到所有其他客户端?

I have try to modify the existing code from the example我尝试修改示例中的现有代码

...python ...python

import socket
import threading
import socketserver

clientList = []
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):

    def handle(self):
        clientList.append(self.client_address)
        print(clientList)
        print("Client List Length : ",len(clientList))

        while True:
            data = str(self.request.recv(1024), 'ascii')
            if(data.upper() == "EXIT"):
                break
            cur_thread = threading.current_thread()
            response = bytes(data, 'utf_8')
            #self.request.sendall(response)

            for cl in range(1,len(clientList)):
                print("sending to : ",clientList[cl])
                self.request.sendto(response,clientList[cl])

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

def passtime():
    pass
if __name__ == "__main__":

    HOST, PORT = "localhost", 50007


server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address



# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)

# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
while server_thread:
   passtime() 
print("Server loop running in thread:", server_thread.name)

... ...

I have a problem with: self.request.sendto(request,clientList[cl])我有一个问题: self.request.sendto(request,clientList[cl])

Only send the request back to the sending client and not the targeted client in the client list.仅将请求发送回发送客户端,而不是客户端列表中的目标客户端。

Edit: I found a Solution, here is it:编辑:我找到了一个解决方案,这是它:

import socket
import threading
import socketserver
import sys
import select

clientList = []
inbox = []


class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
    clients = []    
    msgSend = 0
    def setup(self):
        clientList.append(self.client_address)
        self.clients = list(dict.fromkeys(clientList))
        print(self.clients)
        print("Client List Length : ",len(self.clients))

    def handle(self):
        while True:
            r,w,e = select.select([self.request],[],[],0.01)
            for rs in r:
                if rs == self.request:
                    data = str(self.request.recv(1024),"ascii")
                    if data:
                        inbox.append(data)
                else:
                    if self.msgSend < len(inbox):
                        for elem in range(self.msgSend, len(inbox)):
                            print("server send :",inbox[elem])
                            self.request.sendall(bytes(inbox[elem],'utf-8'))
                        self.msgSend += 1

            if self.msgSend < len(inbox):
                for elem in range(self.msgSend, len(inbox)):
                    print("server send :",inbox[elem])
                    self.request.sendall(bytes(inbox[elem],'utf-8'))
                self.msgSend += 1

    def finish(self):
        for l in range(len(clientList)):
            if self.client_address == clientList[l]:
                clientList.remove(l)

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

def passtime():
    pass



if __name__ == "__main__":

    HOST, PORT = "localhost", 50007
    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
    ip, port = server.server_address

    server_thread = threading.Thread(target=server.serve_forever)


    server_thread.daemon = True
    server_thread.start()
    while server_thread:
       passtime() 


    sys.exit()

I use an inbox method from here and using select.select I am able to check if there is input to be read.我从这里使用收件箱方法并使用select.select我能够检查是否有要读取的输入。

You can use use PySock , a python library that make writing multi-client servers extremally easy.您可以使用PySock ,这是一个 python 库,它使编写多客户端服务器变得极其容易。 You can download it from PyPi, for windows: pip install PySock and for Linux: pip3 install PySock .您可以从 PyPi 下载它,对于 windows: pip install PySock和对于 Linux: pip3 install PySock They have very good boiler plate code on PyPi introduction page.他们在 PyPi 介绍页面上有非常好的样板代码。 You can check it out here or go to GitHub repo for more insights about versions.您可以在此处查看或 go 至GitHub存储库以获取有关版本的更多信息。

I found a Solution, here is it: 我找到了一个解决方案,就是这样:

import socket
import threading
import socketserver
import sys
import select

clientList = []
inbox = []


class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
    clients = []    
    msgSend = 0
    def setup(self):
        clientList.append(self.client_address)
        self.clients = list(dict.fromkeys(clientList))
        print(self.clients)
        print("Client List Length : ",len(self.clients))

    def handle(self):
        while True:
            r,w,e = select.select([self.request],[],[],0.01)
            for rs in r:
                if rs == self.request:
                    data = str(self.request.recv(1024),"ascii")
                    if data:
                        inbox.append(data)
                else:
                    if self.msgSend < len(inbox):
                        for elem in range(self.msgSend, len(inbox)):
                            print("server send :",inbox[elem])
                            self.request.sendall(bytes(inbox[elem],'utf-8'))
                        self.msgSend += 1

            if self.msgSend < len(inbox):
                for elem in range(self.msgSend, len(inbox)):
                    print("server send :",inbox[elem])
                    self.request.sendall(bytes(inbox[elem],'utf-8'))
                self.msgSend += 1

    def finish(self):
        for l in range(len(clientList)):
            if self.client_address == clientList[l]:
                clientList.remove(l)

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

def passtime():
    pass



if __name__ == "__main__":

    HOST, PORT = "localhost", 50007
    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
    ip, port = server.server_address

    server_thread = threading.Thread(target=server.serve_forever)


    server_thread.daemon = True
    server_thread.start()
    while server_thread:
       passtime() 


    sys.exit()

I use an inbox method from here and using select.select I am able to check if there is input to be read. 我从这里使用inbox方法并使用select.select我能够检查是否有要读取的输入。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM