Python 我需要帮助了解线程利用率

Python 我需要帮助了解线程利用率,python,multithreading,networking,server,client,Python,Multithreading,Networking,Server,Client,我正在用命令和其他类型的东西设置一个小服务器,但是,我没有线程功能,当我连接我的服务器时,似乎一切正常,我可以连接第一个客户机“没有”问题,但当我想连接另一个客户机时,它永远不会被连接,代码可以运行,但我可以发送任何我想要的东西,它永远不会显示在其他客户端或服务器上 我已经阅读了线程文档,但即使有示例,我也不明白,有人能给我一些关于如何处理多个客户机的线索吗 服务器代码: #!/usr/bin/python3+x import socket import sys from time import

我正在用命令和其他类型的东西设置一个小服务器,但是,我没有线程功能,当我连接我的服务器时,似乎一切正常,我可以连接第一个客户机“没有”问题,但当我想连接另一个客户机时,它永远不会被连接,代码可以运行,但我可以发送任何我想要的东西,它永远不会显示在其他客户端或服务器上

我已经阅读了线程文档,但即使有示例,我也不明白,有人能给我一些关于如何处理多个客户机的线索吗

服务器代码

#!/usr/bin/python3+x
import socket
import sys
from time import sleep
import threading
import random

HOST = "localhost"
PORT = 33700

MSG_SIZE = 32768
serveur_on = True


CLIENT_NICK_CHAN = {} #clients" nicks dict like {nickname : channel} -> needed to easily know who is where
CLIENT_NICK_SOCKET = {} #clients" dict like {nickname : socket} -> needed to send private message to the nickname's socket easily
CLIENT_NICK_THREAD = {} #clients" dict with like {nick : thread} 


Rand_disconnection_msg = [" has drown in the abyss.", " is disconnected.", " is now in a better place.", " is now a part of our past", " passed away, in really tragic circumstances..."]
CHANNELS = ["main lobby", "test"]
CMD_LIST = [b"HELP",b"NICK",b"JOIN",b"CHANNELS",b"LEAVE"]
COMMANDS = ["/NICK <nickname>: Use only when you\'re connecting, allow you to choose a unique nickname",
            "/JOIN <channel_name>: Allow you to join or create a channel, you can\'t use this command if your are already in another channel than the" + CHANNELS[0],
            "/CHANNELS : Allow you to see every channels on the server with every connected people",
            "/LEAVE : You leave the channel your within and get bringed back to the" + CHANNELS[0],
            "/HELP : Gives you the whole command list",
            "/BYE : Disconnect ou from the server, you have to in the " + CHANNELS[0] + " to use this command"
            ]


class Colors:
    Blue, Cyan, Green, Red, Magenta, Yellow, White =b"\033[94m", b"\033[96m", b"\033[92m", b"\033[91m", b"\033[95m", b"\033[93m", b"\033[0m"
    Normal, Bold, Italics, Thin = b"\033[0m", b"\033[1m", b"\x1B[3m", b"\033[2m"


class thread_client(threading.Thread):
    def __init__(self,conn):
        self.nom = ""
        if(self.nom == ""):
            nickname_input(connexion, self)
            print("nom : " + self.nom.decode("utf8"))
        self.channel = CHANNELS[0]
        self.admin = False
        self.adress = ""
        threading.Thread.__init__(self)
        self.connexion = conn
        print("init done")


    def run(self):   
        while True:
            msgClient = self.connexion.recv(MSG_SIZE)
            if not msgClient or msgClient == b"BYE":
                break
            print(type(self.nom))
            print(type(msgClient))
            str_name = self.nom.decode("utf8")
            msg = str_name + " > " + msgClient.decode("utf8")
            print("string type name is : " + str_name + "\n")
            str_msg = msgClient.decode("utf8")
            print("{} > {}".format(str_name, str_msg))
            for clients in CLIENT_NICK_SOCKET:
                if clients != self.nom:
                    CLIENT_NICK_SOCKET[clients].send(bytes(str_msg,"utf8"))
        self.connexion.send(b"You are now disconnected.\n")
        self.connexion.close()
        del CLIENT_NICK_SOCKET[self.nom.decode("utf8")]
        del CLIENT_NICK_CHAN[self.nom.decode("utf8")]
        rand_leave = random.randint(0, len(Rand_disconnection_msg)-1)
        leaving_msg = Rand_disconnection_msg[rand_leave]
        print(str_name + leaving_msg + "\n")


def nickname_input(client_socket, thread):
    print("now in input nickname")
    msg_nom = client_socket.recv(MSG_SIZE)
    print("msg_nom = " + msg_nom.decode("utf8"))
    msg_nom_arr = msg_nom.split()
    if not msg_nom_arr[0]:
        client_socket.send(b"Please send a non void message")
        nickname_input(client_socket, thread)
    print("msg_nom_arr[0] = " + str(msg_nom_arr[0]))
    if(msg_nom_arr[0] == b"NICK"):
        if(len(msg_nom_arr)== 1):
            client_socket.send(b"Please do not just enter '/NICK' -> you have to type '/NICK <your_nickname>', please proceed again :\n")
            nickname_input(client_socket, thread)
        else:
            thread.nom = msg_nom_arr[1]
    else:
        client_socket.send(b"It seems like you forgot to use '/NICK' before entering your nickname, please proceed again:\n")
        nickname_input(client_socket, thread)
    return   


def print_channels(client_socket, thread):
    client_socket.send(b"Here\'s the current channel list :\n\n")
    for chan in CHANNELS:
        sleep(0.70)
        client_socket.send( bytes(chan,"utf8") + b":\n    current members :\n")
        for chan_user in CLIENT_NICK_CHAN:
            if(CLIENT_NICK_CHAN[chan_user] == chan):
               sleep(0.35)
               if(chan_user == thread.nom):
                    if(thread.admin):
                       client_socket.send(b"          " +Colors.Bold + Colors.Yellow + b"@"+ thread.nom + b"@" + Colors.Normal + b"\n")
                    else:
                        client_socket.send(b"          " +Colors.Bold + Colors.Yellow + thread.nom + Colors.Normal + b"\n")
               else:
                    client_socket.send(b"       " +bytes(chan_user,"utf8") +  b"@\n")
        client_socket.send(b"\n")
    client_socket.send(b"\n")
    return


def join_channel(client_socket, thread, data, data_array):
    if(not data_arr[1]):
        connexion.send(b"Please select a channel you want to join using '/JOIN <channel_name>'\nNote that if the channel you asked for doesn\'t exists a new channel <channel_name> will be created and you will be the administrator of this channel")
        return
    else:
        asked_channel = data_arr[1]
        if( not (asked_channel in CHANNELS)):
            thread.channel = asked_channel
            thread.admin = True
            connexion.send(b"Welcome in " + asked_channel + b" channel, since you\'re the on who created this channel you are granted as administrator for this channel")
            connexion.send(b"Note that being administrator allow you tu use some new commands as '/GRANT', '/REVOKE' or  '/REN', for more information please use '/HELP'")
        else:
            thread.channel = asked_channel
            connexion.send(b"Welcome in " + asked_channel + b" channel !")
    return


SERVER = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
SERVER.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
try:
    SERVER.bind((HOST,PORT))
except socket.error:
    print("Server connexion failed")
    sys.exit()
print("Server is now connected\nWaiting for connexions...\n")


SERVER.listen(5)


connexion, adresse = SERVER.accept()
thread = thread_client(connexion)
thread.start()

print("thread type = " +str(type(thread)) +"\n")
print("thread = ")
print(thread)
connexion.send(bytes("Welcome ","utf8") + Colors.Yellow + Colors.Bold + thread.nom + Colors.Normal)
nick = thread.nom #type -> bytes
str_nick = nick.decode("utf8")
CLIENT_NICK_CHAN[str_nick] = thread.channel
CLIENT_NICK_SOCKET[str_nick] = connexion
CLIENT_NICK_THREAD[str_nick] = thread
print("client list : ")
print(CLIENT_NICK_CHAN)
print("\n")
print("CLIENT_NICK_SOCKET = ")
print(CLIENT_NICK_SOCKET)
print("\n")
while serveur_on:
    conn_msg = str_nick + " joined the chat\n"
    print(conn_msg)
    connexion.send(b"hello world 3\n\n")
    connexion.send(b"*" * 80 + b"\n")
    connexion.send(Colors.Red + Colors.Bold + b"\nWELCOME IN THE MAIN LOBBY \n" + Colors.Normal+b"\nTo enter a channel use '/JOIN <channel_name>'\nthe <channel_name> have to be composed by one world or use underscores to join words\nIf the channel does not exists a new one will be created\n\nNote that you have to be in another channel than the main lobby to chat\n")
    print_channels(connexion, thread)
    connexion.send(b"*" * 80 + b"\n\n")
    while True:
        print("thread list = ")
        print(CLIENT_NICK_THREAD)
        data = connexion.recv(MSG_SIZE) #receiving data from client
        data_arr= data.split() #convert data into an array to check if the first word in the message is "MSG" or not
        print(str_nick +" is now in -> " + thread.channel + "\n") 
        if(data_arr[0] in CMD_LIST):
            if(data.startswith(b"HELP")): #HELP CMD
                for command in COMMANDS:
                    connexion.send(bytes(command,"utf") + b"\n")
            if(data.startswith(b"CHANNELS")): #Channels + current members CMD
               connexion.send(b"\n")
               print_channel(connexion, thread)
               connexion.send(b"\n")
            if(data.startswith(b"JOIN")):
                join_channel(connexion, thread, data, data_arr)
                connexion.send(b"\n")



        else:
            if ((thread.channel != CHANNELS[0]) and (data.startswith("MSG"))):
                for chan_user in thread.channel:
                    chan_user.send(nick + b" > " + bytes(data,"utf8"))
                    print("data = " + data)
            elif (thread.channel == CHANNELS[0]):
                connexion.send(b"You have to be in another channel than the " + bytes(CHANNELS[0], "utf8") + b" to start chating !\nPlease use '/JOIN <channel_name>' or '/HELP' to learn how to join another channel.\n\n")

我只想让多个客户端可以相互通信,但我甚至无法获得两个客户端。

我看到的最大问题是,您只调用了一次
SERVER.accept()
。这意味着您将只接受一个客户端连接。在使用阻塞套接字时,一种典型的方法是在循环中继续执行
SERVER.accept()
,以便继续接受所有客户端套接字。在您
accept()
一个新套接字之后,您将创建一个或多个专用于发送/接收该套接字的新线程,这样您就不会阻塞接受线程。然后你继续接受更多的连接。大概是这样的:

#SERVER:
while serveur_on:
    connexion, adresse = SERVER.accept()

    # Possibly do some limited IO with client socket here, but be careful not
    # to block this thread too long because that will prevent more clients from
    # connecting.

    thread = thread_client(connexion)
    thread.start()

    # No more client IO on this thread, it's the client thread's job now.

您似乎在两个不同的位置拥有与客户端通信的代码(接收消息和发送响应):在
SERVER.accept()之后的主线程上,以及在
thread\u client.run()中。这样做没有意义,它应该都在
thread\u client.run()

这完全是太多的代码了,你需要提供一个最简单可行的完整示例供人们帮助非常感谢你的回答@almiki我将在一个循环中尝试你用accept方法所说的内容,并再次检查我的代码。现在一切正常,问题正是你所说的,我刚刚尝试了3个客户,他们可以连接proprely,再次感谢。
#SERVER:
while serveur_on:
    connexion, adresse = SERVER.accept()

    # Possibly do some limited IO with client socket here, but be careful not
    # to block this thread too long because that will prevent more clients from
    # connecting.

    thread = thread_client(connexion)
    thread.start()

    # No more client IO on this thread, it's the client thread's job now.