简体   繁体   English

Python 中的多线程 TCP 服务器

[英]Multi Threaded TCP server in Python

I have created a simple multi threaded tcp server using python's threding module.我使用python的线程模块创建了一个简单的多线程tcp服务器。 This server creates a new thread each time a new client is connected.每次连接新客户端时,此服务器都会创建一个新线程。

#!/usr/bin/env python

import socket, threading

class ClientThread(threading.Thread):

    def __init__(self,ip,port):
        threading.Thread.__init__(self)
        self.ip = ip
        self.port = port
        print "[+] New thread started for "+ip+":"+str(port)


    def run(self):    
        print "Connection from : "+ip+":"+str(port)

        clientsock.send("\nWelcome to the server\n\n")

        data = "dummydata"

        while len(data):
            data = clientsock.recv(2048)
            print "Client sent : "+data
            clientsock.send("You sent me : "+data)

        print "Client disconnected..."

host = "0.0.0.0"
port = 9999

tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

tcpsock.bind((host,port))
threads = []


while True:
    tcpsock.listen(4)
    print "\nListening for incoming connections..."
    (clientsock, (ip, port)) = tcpsock.accept()
    newthread = ClientThread(ip, port)
    newthread.start()
    threads.append(newthread)

for t in threads:
    t.join()

Then I opened two new terminals and connected to the server using netcat.然后我打开了两个新终端并使用netcat连接到服务器。 Then, when I type and send my first data to the server using the first terminal I connected, reply from the server comes to the other terminal and first connection got disconnected.然后,当我使用我连接的第一个终端输入我的第一个数据并将其发送到服务器时,来自服务器的回复到达另一个终端并且第一个连接断开。 I guessed the reason but I am doubtful whether this happens because clientsock variable is overwritten so that it refers to the second connection's socket.我猜到了原因,但我怀疑这是否会发生,因为clientsock变量被覆盖,因此它指的是第二个连接的套接字。 Am I correct and then how to avoid that?我是否正确,然后如何避免这种情况?

Is there a way other than using an array with limited number of socket variables and using each variable for each connection?除了使用套接字变量数量有限的数组并为每个连接使用每个变量之外,还有其他方法吗?

You should pass the client sock to the thread like you do with the ip address and the port:您应该像处理 IP 地址和端口一样将客户端 sock 传递给线程:

class ClientThread(threading.Thread):

    def __init__(self, ip, port, socket):
        threading.Thread.__init__(self)
        self.ip = ip
        self.port = port
        self.socket = socket
        print "[+] New thread started for "+ip+":"+str(port)

    def run(self):
        # use self.socket to send/receive

...
(clientsock, (ip, port)) = tcpsock.accept()
newthread = ClientThread(ip, port, clientsock)
...

I have created this nice class you can override我创建了这个不错的类,您可以覆盖

import socket
import thread

class SocketServer(socket.socket):
    clients = []

    def __init__(self):
        socket.socket.__init__(self)
        #To silence- address occupied!!
        self.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.bind(('0.0.0.0', 8080))
        self.listen(5)

    def run(self):
        print "Server started"
        try:
            self.accept_clients()
        except Exception as ex:
            print ex
        finally:
            print "Server closed"
            for client in self.clients:
                client.close()
            self.close()

    def accept_clients(self):
        while 1:
            (clientsocket, address) = self.accept()
            #Adding client to clients list
            self.clients.append(clientsocket)
            #Client Connected
            self.onopen(clientsocket)
            #Receiving data from client
            thread.start_new_thread(self.recieve, (clientsocket,))

    def recieve(self, client):
        while 1:
            data = client.recv(1024)
            if data == '':
                break
            #Message Received
            self.onmessage(client, data)
        #Removing client from clients list
        self.clients.remove(client)
        #Client Disconnected
        self.onclose(client)
        #Closing connection with client
        client.close()
        #Closing thread
        thread.exit()
        print self.clients

    def broadcast(self, message):
        #Sending message to all clients
        for client in self.clients:
            client.send(message)

    def onopen(self, client):
        pass

    def onmessage(self, client, message):
        pass

    def onclose(self, client):
        pass

And here's an example:这是一个例子:

class BasicChatServer(SocketServer):

    def __init__(self):
        SocketServer.__init__(self)

    def onmessage(self, client, message):
        print "Client Sent Message"
        #Sending message to all clients
        self.broadcast(message)

    def onopen(self, client):
        print "Client Connected"

    def onclose(self, client):
        print "Client Disconnected"

def main():
    server = BasicChatServer()
    server.run()

if __name__ == "__main__":
    main()

Python3 has ThreadingTCPServer (and others) which can do this for you Python3 有ThreadingTCPServer(和其他)可以为你做这件事

Note the threading here is per request and not per client - this has the disadvantage of a small thread-wind-up time per request, but the advantage that it scales better as the number of clients increases.请注意,这里的线程是针对每个请求而不是每个客户端的- 这具有每个请求的线程结束时间较短的缺点,但其优点是随着客户端数量的增加它可以更好地扩展。

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

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