首页 > 编程问答 >我在制作 python 语音应用程序时遇到错误

我在制作 python 语音应用程序时遇到错误

时间:2024-08-09 02:49:22浏览次数:17  
标签:python server python-multithreading pyaudio python-sockets

我编写了一个语音聊天应用程序代码,但是当我们运行此代码并加入语音频道时,我收到照片中的错误

错误1 错误2

这是我的代码; 客户端代码:

import tkinter as tk
from tkinter import messagebox
import pyaudio
import socket
import threading
import time

HOST = '127.0.0.1'
PORT = 65432


class VoiceChatApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Voice Chat Application")
        self.username = ""
        self.channel = None
        self.is_mic_on = True

        self.setup_gui()
        self.p = pyaudio.PyAudio()
        self.stream = None
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.connect_to_server()
        threading.Thread(target=self.receive_data, daemon=True).start()

    def setup_gui(self):
        self.root.geometry("300x400")
        self.root.configure(bg="#2e2e2e")

        # Title label
        tk.Label(self.root, text="Voice Chat", font=("Helvetica", 16, "bold"), fg="#ffffff", bg="#2e2e2e").pack(pady=10)

        # Username entry
        self.username_entry = tk.Entry(self.root, font=("Helvetica", 12), bg="#ffffff", fg="#000000")
        self.username_entry.insert(0, "Enter username")
        self.username_entry.pack(pady=5, padx=10, fill=tk.X)

        # Set Username button
        tk.Button(self.root, text="Set Username", command=self.set_username, font=("Helvetica", 12), bg="#4CAF50",
                  fg="#ffffff", relief=tk.RAISED).pack(pady=5, padx=10, fill=tk.X)

        # Channel selection
        self.channel_var = tk.StringVar(value="Select Channel")
        self.channel_menu = tk.OptionMenu(self.root, self.channel_var, "Channel1", "Channel2")
        self.channel_menu.config(font=("Helvetica", 12), bg="#ffffff", fg="#000000")
        self.channel_menu.pack(pady=5, padx=10, fill=tk.X)

        # Join Channel button
        tk.Button(self.root, text="Join Channel", command=self.join_channel, font=("Helvetica", 12), bg="#2196F3",
                  fg="#ffffff", relief=tk.RAISED).pack(pady=5, padx=10, fill=tk.X)

        # Leave Channel button
        tk.Button(self.root, text="Leave Channel", command=self.leave_channel, font=("Helvetica", 12), bg="#FFC107",
                  fg="#ffffff", relief=tk.RAISED).pack(pady=5, padx=10, fill=tk.X)

        # Current Channel label
        self.current_channel_label = tk.Label(self.root, text="Current Channel: None", font=("Helvetica", 12),
                                              fg="#ffffff", bg="#2e2e2e")
        self.current_channel_label.pack(pady=5)

        # Mute button
        self.mute_button = tk.Button(self.root, text="Mute Microphone", command=self.toggle_mic, font=("Helvetica", 12),
                                     bg="#F44336", fg="#ffffff", relief=tk.RAISED)
        self.mute_button.pack(pady=5, padx=10, fill=tk.X)

        # User list
        self.user_list_label = tk.Label(self.root, text="Users in Channel:", font=("Helvetica", 12), fg="#ffffff",
                                        bg="#2e2e2e")
        self.user_list_label.pack(pady=5)
        self.user_listbox = tk.Listbox(self.root, font=("Helvetica", 12), bg="#ffffff", fg="#000000")
        self.user_listbox.pack(pady=5, padx=10, fill=tk.BOTH, expand=True)

        # Exit button
        tk.Button(self.root, text="Exit Application", command=self.exit_application, font=("Helvetica", 12),
                  bg="#F44336", fg="#ffffff", relief=tk.RAISED).pack(pady=5, padx=10, fill=tk.X)

    def connect_to_server(self):
        while True:
            try:
                self.socket.connect((HOST, PORT))
                break
            except Exception as e:
                print(f"Connection attempt failed: {e}")
                time.sleep(5)

    def set_username(self):
        self.username = self.username_entry.get()
        if not self.username:
            messagebox.showwarning("Warning", "Username cannot be empty")
        else:
            messagebox.showinfo("Info", f"Username set to {self.username}")

    def join_channel(self):
        self.channel = self.channel_var.get()
        if self.channel in ["Channel1", "Channel2"]:
            message = f"JOIN|{self.channel}|{self.username}"
            try:
                self.socket.send(message.encode())
                self.start_audio_stream()
                self.current_channel_label.config(text=f"Current Channel: {self.channel}")
            except Exception as e:
                messagebox.showerror("Connection Error", f"Unable to send message to server: {e}")
        else:
            messagebox.showwarning("Warning", "Please select a valid channel")

    def leave_channel(self):
        if self.channel:
            message = f"LEAVE|{self.channel}|{self.username}"
            try:
                self.socket.send(message.encode())
                self.stop_audio_stream()
                self.current_channel_label.config(text="Current Channel: None")
                self.channel = None
            except Exception as e:
                messagebox.showerror("Connection Error", f"Unable to send message to server: {e}")
        else:
            messagebox.showwarning("Warning", "You are not in a channel")

    def start_audio_stream(self):
        try:
            device_index = None
            for i in range(self.p.get_device_count()):
                info = self.p.get_device_info_by_index(i)
                if info['maxInputChannels'] > 0:
                    device_index = i
                    break

            if device_index is None:
                raise ValueError("No input device found")

            self.stream = self.p.open(format=pyaudio.paInt16,
                                      channels=1,
                                      rate=44100,
                                      input=True,
                                      input_device_index=device_index,
                                      frames_per_buffer=1024,
                                      stream_callback=self.audio_callback)
        except Exception as e:
            messagebox.showerror("Audio Error", f"Unable to start audio stream: {e}")

    def audio_callback(self, in_data, frame_count, time_info, status):
        if self.is_mic_on:
            try:
                self.socket.sendall(in_data)
            except (BrokenPipeError, ConnectionResetError, ConnectionAbortedError) as e:
                print(f"Audio send error: {e}")
                self.stop_audio_stream()

                messagebox.showerror("Connection Error", "Connection lost while sending audio data")
        return (None, pyaudio.paContinue)

    def stop_audio_stream(self):
        if self.stream:
            try:
                self.stream.stop_stream()
                self.stream.close()
            except IOError as e:
                print(f"Stream stop error: {e}")
            self.stream = None

    def toggle_mic(self):
        self.is_mic_on = not self.is_mic_on
        status = "Muted" if not self.is_mic_on else "Unmuted"
        self.mute_button.config(text=f"Microphone {status}")

    def receive_data(self):
        while True:
            try:
                message = self.socket.recv(1024).decode()
                if message.startswith("UPDATE"):
                    _, channel, users = message.split('|', 2)
                    self.user_listbox.delete(0, tk.END)
                    for user in users.split(', '):
                        self.user_listbox.insert(tk.END, user)
            except (ConnectionResetError, ConnectionAbortedError) as e:
                print(f"Receive data error: {e}")
                self.connect_to_server()
            except Exception as e:
                print(f"Unexpected error: {e}")

    def exit_application(self):
        if self.stream:
            self.stop_audio_stream()
        self.socket.close()
        self.root.destroy()


if __name__ == "__main__":
    root = tk.Tk()
    app = VoiceChatApp(root)
    root.mainloop()

服务器代码:

import socket
import threading


HOST = '127.0.0.1'
PORT = 65432


channels = {"Channel1": [], "Channel2": []}
connections = []

def handle_client(conn, addr):
    print(f"Yeni bağlantı: {addr}")
    try:
        while True:
            message = conn.recv(1024).decode()
            if not message:
                break
            command = message.split('|')
            if command[0] == "JOIN":
                channel = command[1]
                username = command[2]
                if channel in channels:
                    channels[channel].append(username)
                    update_users_in_channel(channel)
            elif command[0] == "LEAVE":
                channel = command[1]
                username = command[2]
                if channel in channels and username in channels[channel]:
                    channels[channel].remove(username)
                    update_users_in_channel(channel)

    except (ConnectionResetError, ConnectionAbortedError) as e:
        print(f"Connection error: {e}")
    finally:
        conn.close()
        connections.remove(conn)
        print(f"Bağlantı kapandı: {addr}")

def update_users_in_channel(channel):
    user_list = ', '.join(channels[channel])
    message = f"UPDATE|{channel}|{user_list}"
    for conn in connections:
        try:
            conn.send(message.encode())
        except (BrokenPipeError, ConnectionResetError) as e:
            print(f"Broadcast error: {e}")
            connections.remove(conn)

def start_server():
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind((HOST, PORT))
    server_socket.listen()
    print("Sunucu başlatıldı ve dinleniyor...")

    while True:
        conn, addr = server_socket.accept()
        connections.append(conn)
        threading.Thread(target=handle_client, args=(conn, addr), daemon=True).start()

if __name__ == "__main__":
    start_server()

我不明白出了什么问题

如果您能帮助我,我将非常感激。

我正在尝试通过制作一个不和谐的副本来提高自己简单的界面。我在编写代码时也得到了 chatgpt 的帮助。但他找不到我遇到的这个错误的解决方案。


代码中有几个问题可能会导致遇到的错误:

客户端问题:

  1. 音频回调中的套接字错误处理: audio_callback 函数中,正在捕获 BrokenPipeError ConnectionResetError ConnectionAbortedError ,但没有清除通道信息或通知服务器已断开连接。这可能会导致服务器尝试将数据发送到一个已关闭的套接字,从而产生“管道损坏”错误。

  2. 缺少退出处理: 当关闭客户端窗口时,没有正确地关闭套接字连接或停止音频流。这可能会导致服务器端出现错误,因为它不知道客户端已断开连接。

服务器端问题:

  1. 广播中的套接字错误处理: update_users_in_channel 函数中,正在迭代所有连接并发送更新。但是,如果其中一个连接断开,将收到错误,并且不会向列表中的其余连接发送更新。

解决方案:

客户端:

  1. audio_callback 中处理断开连接: python def audio_callback(self, in_data, frame_count, time_info, status): if self.is_mic_on: try: self.socket.sendall(in_data) except (BrokenPipeError, ConnectionResetError, ConnectionAbortedError) as e: print(f"Audio send error: {e}") self.stop_audio_stream() self.channel = None # 清除通道信息 self.current_channel_label.config(text="Current Channel: None") messagebox.showerror("Connection Error", "Connection lost while sending audio data") return (None, pyaudio.paContinue)

  2. exit_application 中发送离开消息: python def exit_application(self): if self.channel: self.leave_channel() # 发送离开消息到服务器 if self.stream: self.stop_audio_stream() self.socket.close() self.root.destroy()

服务器端:

  1. update_users_in_channel 中处理断开连接: python def update_users_in_channel(channel): user_list = ', '.join(channels[channel]) message = f"UPDATE|{channel}|{user_list}" for conn in connections[:]: # 迭代连接副本 try: conn.send(message.encode()) except (BrokenPipeError, ConnectionResetError) as e: print(f"Broadcast error: {e}") connections.remove(conn)

通过进行这些更改,将处理套接字错误并防止应用程序在客户端或服务器意外断开连接时崩溃。

其他建议:

  • 考虑使用更强大的网络库,如 asyncio Twisted ,以更好地处理异步套接字通信。
  • 在的代码中添加更多错误检查和日志记录,以帮助调试问题。

希望这些解决方案能帮助解决语音聊天应用程序中的错误。如果有任何其他问题,请告诉我!

标签:python,server,python-multithreading,pyaudio,python-sockets
From: 78849986

相关文章

  • pyocr,一个超酷的Python库!
    pyocr是一个用于光学字符识别(OCR)的Python库,它提供了一个简单的接口,允许开发者将图片中的文本提取出来。这个库是对Tesseract-OCR的封装,使得在Python环境中使用OCR技术变得更加便捷。如何安装pyocr首先,要使用pyocr库,您需要安装它。可以使用pip包管理工具来进......
  • pattern,一款超牛的Python库
    在程序开发中,处理文本数据和进行自然语言处理是常见需求。pattern是一个强大的Python库,专为文本分析而设计,提供了丰富的功能,包括自然语言处理、数据挖掘和网络分析等。它简单易用,让程序员能够快速实现复杂的文本处理任务。如何安装pattern在开始使用pattern库之前,首先......
  • 【Playwright+Python】系列教程(八)鉴权Authentication的使用
    写在前面还是有些絮叨的感觉,官方翻译和某些博主写那个玩楞,基本都是软件直接翻译后的产物。读起来生硬不说,甚至有的时候不到是什么意思,真的是实在不敢恭维。到底是什么意思?就是你已经登陆过一次,在Session、Cookie未失效的情况下,登录过一次后,下次就不用再走一遍登录的过程,从而缩......
  • 基于CNN-GRU-Attention混合神经网络的负荷预测方法(Python代码实现)
    ......
  • Python和AI库NumPy(二):数组创建与操作的深入探索
    目录1.数组创建1.1基本数组创建1.2使用内置函数创建数组1.3特殊数组的创建2.数组的基本操作2.1数组属性2.2数组索引和切片2.3数组的形状操作2.4数组拼接与分割3.数组的数学操作3.1基本算术操作3.2广播机制3.3线性代数运算4.高级数组操作4.1花式......
  • WinServer重新注册NET40报错
    原文链接:https://blog.csdn.net/lsgis2001/article/details/140834026报错:此操作系统版本不支持此选项。管理员应使用“打开或关闭Windows功能”对话框、“服务器管理器”管理工具或dism.exe命令行工具安装/卸载包含IIS8的ASP.NET4.5C:\Users\Administrator>C:\Windows\M......
  • 如何为本地python共享文件网页配置公网地址实现跨网络远程访问
    文章目录前言1.本地文件服务器搭建1.1.Python的安装和设置1.2.cpolar的安装和注册2.本地文件服务器的发布2.1.Cpolar云端设置2.2.Cpolar本地设置3.公网访问测试4.结语前言本文主要介绍如何在Windows系统电脑上使用python这样的简单程序语言,在自己的电脑上搭建一个......
  • 解决端口号占用问题:Spring Boot报错,Web server failed to start. Port 8080 was alrea
    报错信息:Webserverfailedtostart.Port8080wasalreadyinuse.报错原因:端口被占用解决方法:解决方法一:修改端口修改配置文件,加上参数:server.port=8014或者在application.yml文件中添加server:port:8014在访问时,替换对应的端口号即可解决方法二:关闭占用端口的......
  • 基于YOLOv10深度学习的交通信号灯检测识别系统【python源码+Pyqt5界面+数据集+训练代
    《博主简介》小伙伴们好,我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~......
  • 用Python简单操作MySQL!轻松实现数据读写
    PyMySQL是Python编程语言中的一个第三方模块,它可以让Python程序连接到MySQL数据库并进行数据操作。它的使用非常简单,只需要安装PyMySQL模块,然后按照一定的步骤连接到MySQL数据库即可。本文将介绍PyMySQL的安装、连接MySQL数据库、创建表、插入数据、查询数据、更新数据和删除数据......