Python GUI 客户端和服务器连接总是冻结

问题描述 投票:0回答:0

所以我的 python 程序本质上是一个投资界面,客户端显示图形元素,比如第一页是登录或注册页面,然后当用户的凭据针对使用 sqlite 数据库存储所述条目的服务器进行验证时。然后在成功登录后,用户将移至下一个页面,其中实例化了其他元素。我的问题是每次我登录或注册时,按下任一按钮都会冻结整个图形用户界面,我必须硬关闭它。我尝试使用存储 sql 数据库条目的 csv 文件,然后使用 pandas 读取所述 csv 以确认正确的条目,但无济于事。如果此功能不工作,我将无法继续进行。任何帮助深表感谢。多年来一直在尝试调试它。

使用连接到 sql 数据库的 csv 然后 pandas 从所述 csv 读取,不起作用,我注意到没有任何内容被保存但是当运行客户端时,它显示在终端发送然后继续显示在登录/注册中选择的凭据页面,但我猜服务器没有收到这些数据,因此无法存储它们。这是服务器和客户端代码。

Server codes:
import sqlite3
from sqlite3 import Error
import socket
import threading
import pandas as pd
import yfinance as yf
import os

class Database:
    def __init__(self):
        self.conn = self.create_connection()

    def create_connection(self):
        conn = None
        try:
            conn = sqlite3.connect('clients.db')
            print(f'successful connection with sqlite version {sqlite3.version}')
        except Error as e:
            print(e)
        return conn

    def create_table(self, create_table_sql):
        try:
            c = self.conn.cursor()
            c.execute(create_table_sql)
        except Error as e:
            print(e)

    def setup_database(self):
        sql_create_user_table = """CREATE TABLE IF NOT EXISTS clients (
                                    client_id VARCHAR(20) NOT NULL PRIMARY KEY,
                                    password VARCHAR(255) NOT NULL,
                                    age INT,
                                    initial_investment FLOAT,
                                    investment_type VARCHAR(255)
                                    );"""
        self.create_table(sql_create_user_table)

    def create_user(self, user):
        sql = '''INSERT INTO clients(client_id, password, age, initial_investment, investment_type)
                 VALUES(?,?,?,?,?)'''
        cur = self.conn.cursor()
        cur.execute(sql, user)
        self.conn.commit()
        return cur.lastrowid

    def get_all_users(self):
        cur = self.conn.cursor()
        cur.execute("SELECT * FROM clients")
        return cur.fetchall()

    def user_exists(self, client_id, password):
        cur = self.conn.cursor()
        cur.execute("SELECT * FROM clients WHERE client_id = ? AND password = ?", (client_id, password))
        return len(cur.fetchall()) > 0

    def export_to_csv(self, filename):
        df = pd.read_sql_query("SELECT * FROM clients", self.conn)
        df.to_csv(filename, index=False)

    def import_from_csv(self, filename):
        df = pd.read_csv(filename)
        df.to_sql('clients', self.conn, if_exists='replace', index=False)

class AssetManager:
    @staticmethod
    def get_asset_prices():
        assets = ['ETH-USD', 'DOGE-USD', 'BTC-USD', 'GC=F', 'SI=F']
        prices = yf.download(assets, start='2023-03-18', end='2023-03-19')['Close']
        return prices.iloc[-1].to_dict()

class Server:
    def __init__(self, database, asset_manager):
        self.database = database
        self.asset_manager = asset_manager

    def handle_client(self, client_socket):
        while True:
            data = client_socket.recv(1024).decode("utf-8")
            if not data:
                break
            print(f"Received data: {data}")

        request_type, *request_data = data.split("|")

        if request_type == "signup":
            client_id, password, age, initial_investment, investment_type = request_data
            print(f"Signup data: {client_id}, {password}, {age}, {initial_investment}, {investment_type}")
            if not self.database.user_exists(client_id, password):
                self.database.create_user((client_id, password, age, initial_investment, investment_type))
                response = "signup_success|Account created successfully."
            else:
                response = "signup_failure|Account with this ID and password already exists."
        elif request_type == "login":
            client_id, password = request_data
            if self.database.user_exists(client_id, password):
                response = "login_success|Login successful."
            else:
                response = "login_failure|Invalid ID or password."
        elif request_type == "view_portfolio":
            asset_prices = self.asset_manager.get_asset_prices()
            response = "view_portfolio|"
            for asset, price in asset_prices.items():
                response += f"{asset}: {price}\n"

            all_users = self.database.get_all_users()
            response += "\nList of connected users:\n"
            for user in all_users:
                response += f"{user[0]}: {user[1]}\n"
            if request_type in ["signup", "login"]:
                if "success" in response:
                    self.database.export_to_csv('clients.csv')

            client_socket.sendall(response.encode("utf-8"))

    def start(self):
        if not os.path.exists('clients.csv'):
            self.database.export_to_csv('clients.csv')
        self.database.import_from_csv('clients.csv')

        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.bind(('localhost', 5000))
        server.listen(5)
        server.settimeout(5)
        print("Server started. Waiting for connections...")

        while True:
            try:
                client, address = server.accept()
                client.settimeout(5)  # Set the timeout for the new socket
                print(f"Connection from {address} has been established.")
                client_thread = threading.Thread(target=self.handle_client, args=(client,))
                client_thread.start()
            except socket.timeout:
                print("No new connection received. Continuing to wait...")

def main():
    db = Database()
    db.setup_database()
    am = AssetManager()
    server = Server(db, am)
    try:
        server.start()
    except KeyboardInterrupt:
        print("Server stopped. Exporting data to 'clients.csv'...")
        db.export_to_csv('clients.csv')
        print("Data exported successfully.")

if __name__ == "__main__":
    main()

Client Codes:import socket
from tkinter import *
from tkinter import messagebox
from tkinter import simpledialog
import yfinance as yf
import matplotlib.pyplot as plt


class Investment_Interface_App:
    def __init__(self, root):
        self.root = root
        self.root.title("Investment_Interface_App")
        self.root.geometry("400x400")

        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_socket.connect(('localhost', 5000))
        self.client_socket.settimeout(5)

        self.login_signup_frame = Frame(self.root)
        self.login_signup_frame.pack(fill=BOTH, expand=True)

        self.create_login_signup_frame()

    def send_request(self, request):
        client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        client_socket.connect(('localhost', 5000))
        client_socket.sendall(request.encode("utf-8"))
        response = client_socket.recv(4096).decode("utf-8")
        client_socket.close()
        response_type, *response_data = response.split("|")
        if response_type == "signup_success":
            messagebox.showinfo("Success", response_data[0])
        elif response_type == "signup_failure":
            messagebox.showerror("Error", response_data[0])
        elif response_type == "login_success":
            messagebox.showinfo("Success", response_data[0])
            # Add any additional actions to perform upon successful login
        elif response_type == "login_failure":
            messagebox.showerror("Error", response_data[0])
        else:
            messagebox.showerror("Error", "Unknown response type.")
        return response.split("|")

    def login(self):
        self.client_id = self.client_id_entry.get()
        self.password = self.password_entry.get()

        if not self.client_id or not self.password:
            messagebox.showerror("Error", "Please fill in both fields.")
            return

        data = f"login|{self.client_id}|{self.password}"

        response = self.send_request(data)
        if response is None:
            return

        response_status, response_message = response.split("|", 1)
        if response_status == "login_success":
            # Proceed to the next page
            print("Logged in successfully")
        else:
            # Show an error message
            print(f"Login failed: {response_message}")

    def signup(self):
        self.client_id = self.client_id_entry.get()
        self.password = self.password_entry.get()
        self.age = self.age_entry.get()
        self.initial_investment = self.initial_investment_entry.get()

        selected_investment_types = []
        for index in self.investment_type_listbox.curselection():
            selected_investment_types.append(self.investment_type_listbox.get(index))
        self.investment_type = ','.join(selected_investment_types)

        if not self.client_id or not self.password or not self.age or not self.initial_investment or not self.investment_type:
            messagebox.showerror("Error", "Please fill in all fields.")
            return

        if not (18 <= int(self.age) <= 100):
            messagebox.showerror("Error", "Age must be between 18 and 100.")
            return

        data = f"signup|{self.client_id}|{self.password}|{self.age}|{self.initial_investment}|{self.investment_type}"

        response = self.send_request(data)
        if response is None:
            return

        if "|" in response:
            response_status, response_message = response.split("|", 1)
            if response_status == "success":
                messagebox.showinfo("Success", response_message)
            else:
                messagebox.showerror("Error", response_message)
        else:
            messagebox.showerror("Error", f"Unexpected server response: {response}")

    def create_login_signup_frame(self):
        Label(self.login_signup_frame, text="ClientID").grid(row=0, column=0, sticky=W)
        self.client_id_entry = Entry(self.login_signup_frame)
        self.client_id_entry.grid(row=0, column=1)

        Label(self.login_signup_frame, text="Password").grid(row=1, column=0, sticky=W)
        self.password_entry = Entry(self.login_signup_frame, show="*")
        self.password_entry.grid(row=1,column=1)
        self.extra_fields = []
        self.mode = StringVar()
        self.mode.set("login")
        self.mode_button = Button(self.login_signup_frame, text="Switch to Sign Up", command=self.toggle_mode)

        self.action_button = Button(self.login_signup_frame, text="Login", command=self.login_or_signup)

        self.mode_button.grid(row=5, column=0, padx=10, pady=10)
        self.action_button.grid(row=5, column=1, padx=10, pady=10)

    def toggle_mode(self):
        if self.mode.get() == "login":
            self.mode.set("signup")
            self.mode_button.config(text="Switch to Login")
            self.action_button.config(text="Sign Up")
            self.create_signup_frame()
        else:
            self.mode.set("login")
            self.mode_button.config(text="Switch to Sign Up")
            self.action_button.config(text="Login")
            self.remove_signup_frame()

    def create_signup_frame(self):
        age_label = Label(self.login_signup_frame, text="Age")
        age_label.grid(row=3, column=0, sticky=W)
        self.age_entry = Entry(self.login_signup_frame)
        self.age_entry.grid(row=3, column=1)

        initial_investment_label = Label(self.login_signup_frame, text="Initial Investment")
        initial_investment_label.grid(row=4, column=0, sticky=W)
        self.initial_investment_entry = Entry(self.login_signup_frame)
        self.initial_investment_entry.grid(row=4, column=1)

        investment_type_label = Label(self.login_signup_frame, text="Investment Type")
        investment_type_label.grid(row=5, column=0, sticky=W)
        self.investment_type_listbox = Listbox(self.login_signup_frame, selectmode=MULTIPLE)
        self.investment_type_listbox.grid(row=5, column=1)
        for item in ["Ethereum", "Bitcoin", "DogeCoin", "Gold", "Silver"]:
            self.investment_type_listbox.insert(END, item)

        self.extra_fields.extend([age_label, self.age_entry, initial_investment_label, self.initial_investment_entry,
                                  investment_type_label, self.investment_type_listbox])

        self.mode_button.grid(row=6, column=0, padx=10, pady=10)
        self.action_button.grid(row=6, column=1, padx=10, pady=10)

    def remove_signup_frame(self):
        for field in self.extra_fields:
            field.grid_remove()
        self.extra_fields.clear()


    def login_or_signup(self):
        client_id = self.client_id_entry.get()
        password = self.password_entry.get()

        if self.mode.get() == "signup":
            age = self.age_entry.get()
            initial_investment = self.initial_investment_entry.get()
            investment_type = "|".join([self.investment_type_listbox.get(idx) for idx in self.investment_type_listbox.curselection()])
            request = f"signup|{client_id}|{password}|{age}|{initial_investment}|{investment_type}"
        else:
            request = f"login|{client_id}|{password}"

        self.send_request(request)

    def create_account_frame(self):
        self.account_frame = Frame(self.root)
        self.account_frame.pack(fill=BOTH, expand=True)
        self.open_account_button = Button(self.account_frame, text="Open An Account", command=self.open_account)
        self.open_account_button.pack(pady=10)

    def open_account(self):
        self.account_frame.pack_forget()
        self.create_options_frame()

    def create_options_frame(self):
        self.options_frame = Frame(self.root)
        self.options_frame.pack(fill=BOTH, expand=True)

        self.invest_now_button = Button(self.options_frame, text="Invest Now", command=self.invest_now)
        self.invest_now_button.pack(pady=10)

        self.portfolio_viewing_button = Button(self.options_frame, text="Portfolio Viewing",
                                               command=self.view_portfolio)
        self.portfolio_viewing_button.pack(pady=10)

        self.pay_in_out_button = Button(self.options_frame, text="Pay In/Withdraw", command=self.pay_in_out)
        self.pay_in_out_button.pack(pady=10)

    def invest_now(self):
        self.options_frame.pack_forget()
        self.invest_now_frame = Frame(self.root)
        self.invest_now_frame.pack(fill=BOTH, expand=True)

        Label(self.invest_now_frame, text="Investment").grid(row=0, column=0, sticky=W)
        self.investment_choice = StringVar()
        self.investment_menu = OptionMenu(self.invest_now_frame, self.investment_choice,
                                          *["Ethereum", "LiteCoin", "DogeCoin", "Shiba Inu", "Binance Coin", "Gold",
                                            "Silver"])
        self.investment_menu.grid(row=0, column=1)

        Label(self.invest_now_frame, text="Quantity").grid(row=1, column=0, sticky=W)
        self.quantity_entry = Entry(self.invest_now_frame)
        self.quantity_entry.grid(row=1, column=1)

        self.calculate_button = Button(self.invest_now_frame, text="Calculate Value", command=self.calculate_value)
        self.calculate_button.grid(row=2, column=1, pady=10)

    def calculate_value(self):
        investment = self.investment_choice.get()
        quantity = float(self.quantity_entry.get())

        data = f"get_current_price|{investment}"

        response = self.send_request(data)
        if response is None:
            return

        current_price = float(response)

        value = current_price * quantity
        messagebox.showinfo("Investment Value", f"The value of {quantity} {investment} is ${value:.2f}")

    def get_latest_prices(self, investment_types):
        ticker_symbols = {
            "Gold": "GC=F",
            "Silver": "SI=F",
            "Ethereum": "ETH-USD",
            "Bitcoin": "BTC-USD",
            "DogeCoin": "DOGE-USD"
        }

        prices = {}
        for investment in investment_types:
            ticker = yf.Ticker(ticker_symbols[investment])
            latest_price = ticker.info["regularMarketPrice"]
            prices[investment] = latest_price

        return prices

    def view_portfolio(self):
        data = f"view_portfolio|{self.client_id}"

        response = self.send_request(data)
        if response is None:
            return

        if response.startswith("success"):
            portfolio = response[8:]
            investment_types = portfolio.split(",")

            # Get the latest prices
            latest_prices = self.get_latest_prices(investment_types)

            # Calculate the value of each investment type
            quantities = [1, 2, 3]  # Replace this with the actual quantities of the investments
            values = [quantities[i] * latest_prices[investment] for i, investment in  `your text`enumerate(investment_types)]

            # Generate a bar chart
            plt.bar(investment_types, values)
            plt.xlabel("Investment Types")
            plt.ylabel("Value")
            plt.title("Portfolio")
            plt.show()

            messagebox.showinfo("Portfolio", f"Your portfolio: {portfolio}")
        else:
            messagebox.showerror("Error", "Failed to fetch portfolio.")


    def pay_in_out(self):
        self.options_frame.pack_forget()
        self.pay_in_out_frame = Frame(self.root)
        self.pay_in_out_frame.pack(fill=BOTH, expand=True)

        self.pay_in_button = Button(self.pay_in_out_frame, text="Pay In", command=self.pay_in)
        self.pay_in_button.pack(pady=10)
        self.withdraw_button = Button(self.pay_in_out_frame, text="Withdraw", command=self.withdraw)
        self.withdraw_button.pack(pady=10)

    def pay_in(self):
        amount = simpledialog.askfloat("Pay In", "Enter the amount to pay in:", parent=self.root, minvalue=0)
        if amount is None:
            return

        data = f"pay_in|{amount}"

        response = self.send_request(data)
        if response is None:
            return

        if response == "success":
            messagebox.showinfo("Success", f"${amount:.2f} has been successfully added to your account.")
        else:
            messagebox.showerror("Error", "Failed to pay in.")

    def withdraw(self):
        amount = simpledialog.askfloat("Withdraw", "Enter the amount to withdraw:", parent=self.root, minvalue=0)
        if amount is None:
            return

        data = f"withdraw|{amount}"

        response = self.send_request(data)
        if response is None:
            return

        if response == "success":
             messagebox.showinfo("Success", f"${amount:.2f} has been successfully withdrawn from your account.")
        else:
            messagebox.showerror("Error", "Failed to withdraw.")



if __name__ == "__main__":
    root = Tk()
    app = Investment_Interface_App(root)
    root.mainloop()
python sockets user-interface tkinter freeze
© www.soinside.com 2019 - 2024. All rights reserved.