多客户端的Socket服务器

2024-04-29 14:19:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我刚开始编写python。 我的目标是建造一个有三个屏幕的数码相框。因此,我使用3个Raspis,每个监视器一个。 为了这些raspi的通信,我需要编写一个服务器和一个客户端。你知道吗

对于第一个测试,我想构建一个服务器,它能够向多个客户机发送和接收消息。 所以我从一些socket教程开始,创建了以下程序。你知道吗

服务器类(TcpServer.py文件)你知道吗

class TcpServer:
    clients = []

    serverIsRunning = 0
    port = 0

    def __init__(self, port):
        self.port = port
        self.serverIsRunning = 0
        self.serverRunning = 0



    def startServer (self):
        print("start Server...")
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
        self.server.bind(("", self.port))                                     
        self.server.listen(1)                                            
        self.serverRunning = 1
        while self.serverRunning: 
            read, write, oob = select.select([self.server] + self.clients, [], []) 
            for sock in read: 
                if sock is self.server: 
                    client, addr = self.server.accept() 
                    self.clients.append(client) 
                    print ("+++ Client ", addr[0], " verbunden")
                else: 
                    nachricht = sock.recv(1024) 
                    ip = sock.getpeername()[0] 
                    if nachricht: 
                        print (ip, nachricht) 
                    else: 
                        print ("+++ Verbindung zu ", ip , " beendet")
                        sock.close() 
                        self.clients.remove(sock) 
        for c in self.clients: 
            c.close()
            self.clients.remove(c) 
        self.server.close()

    def send(self, message):
        message = message.encode()
        self.server.send(message)

客户端类(TcpClient.py文件)你知道吗

import socket

class TcpClient:

    def __init__(self, ip, port):
        self.serverAdress = (ip, port)
        self.connected = 0
        self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connection.connect(self.serverAdress)
        print ("connectet to ", self.serverAdress)

    def send(self, message):
        message = message.encode()
        self.connection.send(message)

服务器:

import threading
import TcpServer

tcpServer = TcpServer.TcpServer(50000)

threadTcpServer = threading.Thread(target = tcpServer.startServer)
threadTcpServer.start()

while True:
    tcpServer.send(input("Nachricht eingeben: "))

客户:

import threading
import TcpClient

tcpClient = TcpClient.TcpClient("192.168.178.49", 50000)

while True:
    tcpClient.send(input("Nachricht eingeben: "))

我可以将消息从客户端发送到服务器,但是当我要将消息从服务器发送到客户端时,它会生成以下错误:

BrokenPipeError: [Errno 32] Broken pipe

我假设这是因为服务器线程在等待传入消息时阻塞了套接字。但我不知道怎么处理。 如何编程一个可以发送和接收消息的服务器?你能推荐一个教程吗?我没有找到一个教程来描述我的问题的解决方案。你知道吗

编辑:

现在我试着用socketserver库来解决这个问题,但是我仍然不能解决这个问题。 以下是我的服务器新代码:

import socketserver
import threading
import time

class MyTCPHandler(socketserver.BaseRequestHandler):
    """
    The RequestHandler class for our server.

    It is instantiated once per connection to the server, and must
    override the handle() method to implement communication to the
    client.
    """

    def handle(self):
        # self.request is the TCP socket connected to the client
        self.data = self.request.recv(1024).strip()
        print("{} wrote:".format(self.client_address[0]))
        print(self.data)
        # just send back the same data, but upper-cased
        self.request.sendall(self.data.upper())

if __name__ == "__main__":
    HOST, PORT = "localhost", 9999

    # Create the server, binding to localhost on port 9999
    server = socketserver.TCPServer((HOST, PORT), MyTCPHandler)

    # Activate the server; this will keep running until you
    # interrupt the program with Ctrl-C
    threadTcpServer = threading.Thread(target = server.serve_forever)
    threadTcpServer.start()

    print("server started")

    time.sleep(10)

    print("sending Data")
    server.request.sendall("Server is sending...")

它生成错误:

AttributeError: 'TCPServer' object has no attribute 'request'

我的目标是用一个线程编写一个服务器,该线程接收数据,但仍然能够从另一个线程发送数据。 只有一个插座就可以吗?你知道吗


Tags: thetoimportself服务器send消息message
2条回答

您应该使用提供的socketserver,而不是编写套接字和select等的所有处理

你的代码有多个问题-

1-服务器正在尝试写入侦听套接字!!客户机通信套接字是您从accept()调用获得的套接字,也是您必须用于读写的套接字。你知道吗

2-客户端正在发送数据并立即完成,但它确实应该等待得到响应。否则,python/OS将在程序完成后立即关闭客户机套接字,并且通常在服务器有机会响应之前关闭。你知道吗

我相信有了处理程序代码,您就能够在服务器上接收客户机发送的数据,也能够将一些数据从处理程序发送回客户机?您一定知道,除非有一个客户机连接到服务器,否则服务器不能将任何数据发送回去?你知道吗

现在,要从“另一个”线程向客户机(或多个客户机)发送数据,您需要一种方法使处理程序对象或客户机套接字(在处理程序对象内可用为self.request)对“另一个”线程可用。你知道吗

一种方法是重写def __init__(self, request, client_address, server):方法并将this对象的引用保存在全局列表中。记住在重写的init的最后一行执行以下操作-

# BaseRequestHandler __init__ must be the last statement as all request processing happens in this method
socketserver.BaseRequestHandler.__init__(self, request, client_address, server)

一旦全局列表中有了所有客户机处理程序,就可以根据需要从任何线程轻松地向所有客户机写入数据。您必须阅读有关同步(锁)的内容,并理解从多个线程使用同一对象/套接字可能会给应用程序带来一些逻辑/数据问题。你知道吗

另一件您必须担心的事情和代码是,每当客户机关闭连接时,都要清理这个全局列表。你知道吗

相关问题 更多 >