具有多个客户端的套接字服务器

时间:2018-11-03 11:29:23

标签: python raspberry-pi

我刚刚开始编程python。 我的目标是建立具有三个屏幕的数码相框。因此,我使用3个Raspis,每个监视器一个。 为了与这些Raspis进行通信,我需要对服务器和客户端进行编程。

对于第一个测试,我想构建一个服务器,该服务器能够向/从多个客户端发送和接收消息。 因此,我从一些套接字教程开始,并创建了以下程序。

服务器类(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]管道损坏

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

编辑:

现在我试图用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”对象没有属性“ request”

我的目标是编写一个带有线程的服务器,该线程既可以接收数据又可以从另一个线程发送数据。 即使只有一个插槽,这是否有可能?

2 个答案:

答案 0 :(得分:0)

您应该使用提供的socketserver而不是编写所有套接字的处理并选择etc。

您的代码有多个问题-

1-服务器正在尝试写入侦听套接字!客户端通信套接字是您从accept()调用获得的套接字,而这是您用于读写的套接字。

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

答案 1 :(得分:0)

我相信使用Handler代码,您既可以接收服务器上客户端发送的数据,又可以将某些数据从Handler发送回客户端?您必须已经了解,除非有客户端连接,否则服务器无法发送任何数据?

现在,要从“另一个”线程向客户端(或多个客户端)发送数据,您将需要一种方法来使处理程序对象或客户端套接字(在处理程序对象内部以def predict(): os.system('notepad cmnd.txt') subprocess.call(['C:/Windows/System32/bash.exe']) print(file_contents) label = Label(master, text=file_contents) #subprocess.call(['c:/users/hp/open.py']) label.pack() 可用) “另一个”线程。

一种方法是重写self.request方法并将def __init__(self, request, client_address, server):对象的引用保存在全局列表中。请记住,将以下操作作为被覆盖的 init -

的最后一行
this

一旦所有客户端处理程序都位于全局列表中,就可以根据需要从任何线程轻松地写入所有客户端。您必须阅读有关同步(锁)的知识,并了解从多个线程使用相同的对象/套接字会在您的应用程序中造成一些逻辑/数据问题。

您还需要担心并编写代码的另一件事是,每当客户端关闭连接时,都会清理此全局列表。