python - 在 Python 中创建一个简单的聊天应用程序(套接字)

标签 python multithreading sockets synchronization chat

我正在尝试使用套接字 (python) 创建一个简单的聊天应用程序。客户端可以向服务器发送消息,而服务器只需将消息广播给除发送消息的客户端之外的所有其他客户端。

客户端有两个线程,一直在运行

send: Send simply sends the cleints message to server.

receive: Receive the message from the server.

Server也有两个线程,一直在运行

accept_cleint: To accept the incoming connection from the client.

broadcast_usr: Accepts the message from the client and just broadcast it to all other clients.

但是我得到了错误的输出(请引用下图)。所有线程都应该一直处于事件状态,但有时客户端可以发送消息,有时却不能。例如,Tracey 发送了 4 次“嗨”但没有广播,当约翰说“再见”2 次然后 1 次它的消息被广播。服务器似乎有一些线程同步问题,我不确定。请告诉我怎么了。

enter image description here

下面是代码。

聊天客户端.py

import socket, threading

def send():
    while True:
        msg = raw_input('\nMe > ')
        cli_sock.send(msg)

def receive():
    while True:
        sen_name = cli_sock.recv(1024)
        data = cli_sock.recv(1024)

        print('\n' + str(sen_name) + ' > ' + str(data))

if __name__ == "__main__":   
    # socket
    cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # connect
    HOST = 'localhost'
    PORT = 5023
    cli_sock.connect((HOST, PORT))     
    print('Connected to remote host...')
    uname = raw_input('Enter your name to enter the chat > ')
    cli_sock.send(uname)

    thread_send = threading.Thread(target = send)
    thread_send.start()

    thread_receive = threading.Thread(target = receive)
    thread_receive.start()

聊天服务器.py

import socket, threading

def accept_client():
    while True:
        #accept    
        cli_sock, cli_add = ser_sock.accept()
        uname = cli_sock.recv(1024)
        CONNECTION_LIST.append((uname, cli_sock))
        print('%s is now connected' %uname)

def broadcast_usr():
    while True:
        for i in range(len(CONNECTION_LIST)):
            try:
                data = CONNECTION_LIST[i][1].recv(1024)
                if data:
                    b_usr(CONNECTION_LIST[i][1], CONNECTION_LIST[i][0], data)
            except Exception as x:
                print(x.message)
                break

def b_usr(cs_sock, sen_name, msg):
    for i in range(len(CONNECTION_LIST)):
        if (CONNECTION_LIST[i][1] != cs_sock):
            CONNECTION_LIST[i][1].send(sen_name)
            CONNECTION_LIST[i][1].send(msg)

if __name__ == "__main__":    
    CONNECTION_LIST = []

    # socket
    ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # bind
    HOST = 'localhost'
    PORT = 5023
    ser_sock.bind((HOST, PORT))

    # listen    
    ser_sock.listen(1)
    print('Chat server started on port : ' + str(PORT))

    thread_ac = threading.Thread(target = accept_client)
    thread_ac.start()

    thread_bs = threading.Thread(target = broadcast_usr)
    thread_bs.start()

最佳答案

好的,我之前在评论中撒了谎,抱歉。问题实际上出在服务器上的 broadcast_usr() 函数中。它在 recv() 方法中阻塞,并在 for 循环中阻止除当前选定用户之外的所有用户同时讲话。为了解决这个问题,我更改了 server.py 程序,为它接受的每个客户端连接生成一个新的 broadcast_usr 线程。我希望这会有所帮助。

import socket, threading

def accept_client():
    while True:
        #accept    
        cli_sock, cli_add = ser_sock.accept()
        uname = cli_sock.recv(1024)
        CONNECTION_LIST.append((uname, cli_sock))
        print('%s is now connected' %uname)
        thread_client = threading.Thread(target = broadcast_usr, args=[uname, cli_sock])
        thread_client.start()

def broadcast_usr(uname, cli_sock):
    while True:
        try:
            data = cli_sock.recv(1024)
            if data:
                print "{0} spoke".format(uname)
                b_usr(cli_sock, uname, data)
        except Exception as x:
            print(x.message)
            break

def b_usr(cs_sock, sen_name, msg):
    for client in CONNECTION_LIST:
        if client[1] != cs_sock:
            client[1].send(sen_name)
            client[1].send(msg)

if __name__ == "__main__":    
    CONNECTION_LIST = []

    # socket
    ser_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # bind
    HOST = 'localhost'
    PORT = 5023
    ser_sock.bind((HOST, PORT))

    # listen    
    ser_sock.listen(1)
    print('Chat server started on port : ' + str(PORT))

    thread_ac = threading.Thread(target = accept_client)
    thread_ac.start()

    #thread_bs = threading.Thread(target = broadcast_usr)
    #thread_bs.start()

关于python - 在 Python 中创建一个简单的聊天应用程序(套接字),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36060346/

相关文章:

C++:在 "try"外部创建的类型会导致错误,但在内部则不会

python - Django 管理员在添加/编辑表单中管理外键

python - 从列表中查找基因名称到数据框

具有默认参数的 Python 类构造函数

android - 在 Android 上,应用程序在线程中运行无限循环时崩溃。

c# - 线程必须是 STA-Thread,但它已经是

python - 对齐两个数据框列并保留顺序(没有字典顺序重新排序

c++ - 指向用户定义对象的 C++ 指针是否可以线程安全读取?

ios - 在 swift iOS 应用程序中将参数发送到套接字

c - 如何在 fastcgi 中获取 sendfile() 的浏览器套接字? (在C中)