简体   繁体   English

Python中的聊天模拟器无法正常工作

[英]Chat simulator in Python not working as expected

What I am trying to do is basically simulate a client-server-client chat using threads. 我想要做的基本上是使用线程模拟客户端-服务器-客户端聊天。 Here is the code so far: 这是到目前为止的代码:

from socket import *
from threading import Thread
import threading
import time
from random import randint

clients = []
HOST = 'localhost'
PORT = 8000

class Server():
    def __init__(self):        
        self.addr = (HOST,PORT)
        global clients

        self.start()
        for i in range(5): Thread(target=self.clientHandler).start()

        self.s.close()

    def clientHandler(self): 
        conn, addr = self.s.accept() 
        clients.append(addr)

        print addr[1], "is Connected" 
        while 1: 
            time.sleep(5)

            # message=repr(data)
            # message=message[1:-1].split(':')
            message='test'                               #for debug
            conn.sendto(message, clients[1])             #for debug
            # conn.sendto(message[1], clients[int(message[0])])

    def start(self):    
        self.s = socket(AF_INET, SOCK_STREAM)
        self.s.bind((HOST, PORT))
        self.s.listen(5)

        print "Server is running......"


class Client(threading.Thread):
    global clients
    def sendMessage(self):
        if len(clients)>1:
                to=randint(0, len(clients)-1)
                message = str(to)+':hello from '+self.name
                print message
                self.ss.send(message)

    def receiveMessage(self):        
        while 1:
            reply=self.ss.recv(1024)
            if reply != '':
                print self.name+" received ", repr(reply)
                break

    def run(self):    
        self.ss = socket(AF_INET, SOCK_STREAM)
        self.ss.connect((HOST, PORT)) # client-side, connects to a host
        self.name=self.ss.getsockname()[1]

        while True: 
            # time.sleep(randint(1,5))
            # self.sendMessage()
            self.receiveMessage()

server=Server()
client1=Client()
client2=Client()
client3=Client()

client1.start()
client2.start()
client3.start()

The idea is that one client should send a message to another random one (have not considered excluding itself yet) over and over again. 这个想法是,一个客户端应该一次又一次地向另一个随机的客户端(尚未考虑将其自身排除)发送消息。 To do so, the message has the format dest: message , where dest is a random index for choosing a client from the clients list. 为此,消息的格式为dest: message ,其中dest是用于从clients列表中选择客户端的随机索引。

After hours of "debugging", I discovered that the sendto() method sends the message to all the clients, not just the one with the specified address (as the above code does). 经过数小时的“调试”,我发现sendto()方法将消息发送给所有客户端,而不仅仅是具有指定地址的客户端(如上面的代码那样)。 Am I using it wrong? 我使用错了吗?

Also, when I make the clients send messages, they just receive the message right back. 另外,当我让客户发送邮件时,他们只是刚收到邮件。 What am I doing wrong? 我究竟做错了什么?

I know it is messy, and sorry about that. 我知道这很麻烦,对此感到抱歉。 I just started working with Python and I am testing multiple methods to see how they work. 我刚刚开始使用Python,并且正在测试多种方法以查看它们如何工作。

Thank you. 谢谢。 - Python Noob -Python菜鸟

Your code works since the second argument to sendto is ignored for TCP sockets. 您的代码有效,因为TCP套接字会忽略sendto的第二个参数。

For your idea to work, you must actually read something on the server. 为了使您的想法可行,您实际上必须在服务器上阅读一些内容。 But first, let's look at the other obvious problems: 但是首先,让我们看一下其他明显的问题:

You are creating exactly 5 threads on the server. 您正在服务器上创建5个线程。 This is not harmful yet, but may be in the future. 这还不是有害的,但可能会在将来。 Instead, just create a thread when needed, as in 相反,仅在需要时创建一个线程,如

class Server(threading.Thread):
    def __init__(self):
        super(Server, self).__init__()
        self.addr = (HOST,PORT)
        self.start()

    def run(self):
        self.s = socket(AF_INET, SOCK_STREAM)
        self.s.bind((HOST, PORT))
        self.s.listen(5)
        print "Server is running......"

        while True:
            conn, addr = self.s.accept()
            threading.Thread(target=self.clientHandler, args=(conn, addr)).start()

Then, don't store the address, store the socket: 然后,不存储地址,存储套接字:

def clientHandler(self, conn, addr):
    clients.append(conn)

Furthermore, in clientHandler , read from the sockets: 此外,在clientHandler ,从套接字读取:

def clientHandler(self, conn, addr):
    clients.append(conn)
    while True:
         msg = read_from_socket(conn)
         id_str, _, msg = msg.partition(b':')
         clients[int(id_str.decode('ascii'))].sendall(msg)

read_from_socket must be a function that reads your message format. read_from_socket必须是读取消息格式的函数。 Since TCP is packet-less (imagine it as one infinite stream, until the remote end closes), you must define a message format. 由于TCP是无数据包的(将其想象成一个无限的流,直到远端关闭),因此必须定义一种消息格式。 Let's do that now, by waiting for the newline b'\\n' : 现在,通过等待换行b'\\n'

def read_from_socket(conn):
    buf = bytearray(0)
    while True:
        b = conn.recv(1)
        buf.extend(b)
        if b == b'\n':
             return bytes(buf)

Then we simply have to adapt the client to add a \\n byte: 然后,我们只需调整客户端以添加一个\\n字节:

class Client(threading.Thread):
    def sendMessage(self):
        if len(clients)>1:
                to = randint(0, len(clients) - 1)
                message = ('%s:hello from %s\n' % (to, self.name)).encode('utf-8')
                print(message)
                self.ss.send(message)

Finally, make sure to actually send a message (at the moment, you don't): 最后,请确保实际发送一条消息(此刻您尚未发送):

server=Server()
client1=Client()
client2=Client()
client3=Client()

client1.start()
client2.start()
client3.start()

time.sleep(1)
client1.sendMessage()

Here is the entire code . 这是完整的代码

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

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