09. 多线程版UDP聊天室

发布时间 2023-11-09 09:43:43作者: 星河映梦

一、UDP聊天室

from socket import socket
from socket import AF_INET, SOCK_DGRAM, SOL_SOCKET, SO_REUSEADDR
from time import ctime
from threading import Thread
from queue import Queue

HOST = "127.0.0.1"
PORT = 8080
ADDRESS = (HOST, PORT)

udp_socket = socket(AF_INET, SOCK_DGRAM)                            # 创建服务器套接字
udp_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)                  # 解决端口占用问题
udp_socket.bind(ADDRESS)                                            # 套接字与地址绑定

def send_msg(q):
    while True:
        dest_ip = input("请输入对方的IP地址:").strip()
        dest_port = int(input("请输入对方的PORT:").strip())
        while True:
            msg = input("请输入要发送的数据:").strip()
            if not msg:
                break
            udp_socket.sendto(f"{msg}".encode("utf-8"), (dest_ip, dest_port))
            info = f"【{ctime()}】向【{(dest_ip, dest_port)}】发送数据:{msg}"
            q.put(info)

def recv_msg(q):
    while True:
        try:
            msg, dest_address = udp_socket.recvfrom(1024)           # 服务端接收消息,单次最大接收为1024个字节
            info = f"【{ctime()}】收到【{dest_address}】发送的数据:{msg.decode('utf-8')}"
            q.put(info)
            print(info)
        except:
            pass

def chat_history(q):
    while True:
        content = q.get()                                           # 从Queue中读取数据
        # 将数据写入到文件中
        with open("./chat.txt", "a", encoding="utf-8") as f:
            f.write(content)
            f.write("\n")

if __name__ == "__main__":
    q = Queue()                                                     # 创建一个队列

    send_msg_thread = Thread(target=send_msg, args=(q,))            # 创建一个新的线程对象,用来发送数据
    recv_msg_thread = Thread(target=recv_msg, args=(q,))            # 创建一个新的线程对象,用来接受数据
    chat_history_thread = Thread(target=chat_history, args=(q,))    # 创建一个新的线程对象,用来保存聊天记录

    send_msg_thread.start()
    recv_msg_thread.start()
    chat_history_thread.start()

    send_msg_thread.join()
    recv_msg_thread.join()
    chat_history_thread.join()

    udp_socket.close()