From 8e6adb52599c1fe6f01b1fc8f1d4f27934219cea Mon Sep 17 00:00:00 2001 From: lsy2246 Date: Tue, 23 Apr 2024 22:05:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=AA=E5=86=99=E4=BA=86=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E8=81=8A=E5=A4=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Chat_Room_Second/Client/Page/Call.py | 9 + .../Client/Page/Chat_main.py} | 94 ++++-- .../Chat_Room_Second/Client/Page/Login.py | 270 ++++++++++++++++++ .../Chat_Room_Second/Client/Page/__init__.py | 2 + .../Client/Transmission/File_operate.py | 103 +++++++ .../Client/Transmission/Process_Client.py | 31 ++ .../Client/Transmission/Process_Server.py | 52 ++++ .../Client/Transmission/Session_server.py | 85 ++++++ .../Client/Transmission/__init__.py | 4 + .../Chat_Room_Second/Client/__init__.py | 16 ++ .../Chat_Room_Second/Client/image/chat.png | Bin 0 -> 2871 bytes .../Chat_Room_Second/Client/image/connect.png | Bin 0 -> 2108 bytes .../Chat_Room_Second/Client/image/file.png | Bin 0 -> 23101 bytes .../Chat_Room_Second/Client/image/find.png | Bin 0 -> 1347 bytes .../Chat_Room_Second/Client/image/picture.png | Bin 0 -> 18674 bytes .../Chat_Room_Second/Client/image/site.png | Bin 0 -> 4257 bytes .../Chat_Room_Second/Client/image/speech.png | Bin 0 -> 21178 bytes .../Chat_Room_Second/Client/image/video.png | Bin 0 -> 7236 bytes .../Server/Transmission/Database_formula.py | 181 ++++++++++++ .../Server/Transmission/Process_Client.py | 30 ++ .../Server/Transmission/Process_Server.py | 49 ++++ .../Server/Transmission/Session_client.py | 127 ++++++++ .../Server/Transmission/__init__.py | 4 + .../Chat_Room_Second/Server/__init__.py | 11 + .../chat_room/Chat_Room_Second/StartClient.py | 4 + .../chat_room/Chat_Room_Second/StartServer.py | 4 + .../chat_room/Chat_Room_Second/start_all.py | 6 + python/test/test2.py | 30 -- 28 files changed, 1052 insertions(+), 60 deletions(-) create mode 100644 python/code/chat_room/Chat_Room_Second/Client/Page/Call.py rename python/{test/test.py => code/chat_room/Chat_Room_Second/Client/Page/Chat_main.py} (75%) create mode 100644 python/code/chat_room/Chat_Room_Second/Client/Page/Login.py create mode 100644 python/code/chat_room/Chat_Room_Second/Client/Page/__init__.py create mode 100644 python/code/chat_room/Chat_Room_Second/Client/Transmission/File_operate.py create mode 100644 python/code/chat_room/Chat_Room_Second/Client/Transmission/Process_Client.py create mode 100644 python/code/chat_room/Chat_Room_Second/Client/Transmission/Process_Server.py create mode 100644 python/code/chat_room/Chat_Room_Second/Client/Transmission/Session_server.py create mode 100644 python/code/chat_room/Chat_Room_Second/Client/Transmission/__init__.py create mode 100644 python/code/chat_room/Chat_Room_Second/Client/__init__.py create mode 100644 python/code/chat_room/Chat_Room_Second/Client/image/chat.png create mode 100644 python/code/chat_room/Chat_Room_Second/Client/image/connect.png create mode 100644 python/code/chat_room/Chat_Room_Second/Client/image/file.png create mode 100644 python/code/chat_room/Chat_Room_Second/Client/image/find.png create mode 100644 python/code/chat_room/Chat_Room_Second/Client/image/picture.png create mode 100644 python/code/chat_room/Chat_Room_Second/Client/image/site.png create mode 100644 python/code/chat_room/Chat_Room_Second/Client/image/speech.png create mode 100644 python/code/chat_room/Chat_Room_Second/Client/image/video.png create mode 100644 python/code/chat_room/Chat_Room_Second/Server/Transmission/Database_formula.py create mode 100644 python/code/chat_room/Chat_Room_Second/Server/Transmission/Process_Client.py create mode 100644 python/code/chat_room/Chat_Room_Second/Server/Transmission/Process_Server.py create mode 100644 python/code/chat_room/Chat_Room_Second/Server/Transmission/Session_client.py create mode 100644 python/code/chat_room/Chat_Room_Second/Server/Transmission/__init__.py create mode 100644 python/code/chat_room/Chat_Room_Second/Server/__init__.py create mode 100644 python/code/chat_room/Chat_Room_Second/StartClient.py create mode 100644 python/code/chat_room/Chat_Room_Second/StartServer.py create mode 100644 python/code/chat_room/Chat_Room_Second/start_all.py delete mode 100644 python/test/test2.py diff --git a/python/code/chat_room/Chat_Room_Second/Client/Page/Call.py b/python/code/chat_room/Chat_Room_Second/Client/Page/Call.py new file mode 100644 index 0000000..3730b94 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Client/Page/Call.py @@ -0,0 +1,9 @@ +import wx + +class voice_frame(wx.Frame): + def __init__(self,Id): + super().__init__() + panel = wx.Panel(self) + box = wx.BoxSizer(wx.VERTICAL) + + diff --git a/python/test/test.py b/python/code/chat_room/Chat_Room_Second/Client/Page/Chat_main.py similarity index 75% rename from python/test/test.py rename to python/code/chat_room/Chat_Room_Second/Client/Page/Chat_main.py index 79b3f6a..cfcee36 100644 --- a/python/test/test.py +++ b/python/code/chat_room/Chat_Room_Second/Client/Page/Chat_main.py @@ -4,11 +4,10 @@ import wx import time import multiprocessing - from Client.Transmission.Process_Client import ProcessClient -class ChatFrame(wx.Frame,ProcessClient): +class ChatFrame(wx.Frame, ProcessClient): def __init__(self, Id): wx.Frame.__init__(self, None, size=(800, 600), title="账号: " + str(Id)) ProcessClient.__init__(self) @@ -91,11 +90,6 @@ class ChatFrame(wx.Frame,ProcessClient): ChatMain_Panel.SetSizer(ChatMain_box) - self.root_path = rf'.\{Id}' - self.Account_path = self.root_path + r'\Account.csv' - self.Contacts_path = self.root_path + r'\Contacts.csv' - self.History_path = self.root_path + r'\History.csv' - def click_chat_button(self, event): self.chat_page.Hide() self.connect_page.Hide() @@ -120,19 +114,6 @@ class ChatFrame(wx.Frame,ProcessClient): self.site_page.Show() self.Layout() - def send_Chat_history(self, Contact, send, receive, Type, data, UpDataTime): - chat_panel = self.chat_page.chat_page_map[Contact] - if Type == 'text': - contents = ['My' if Contact == send else 'Ta'] - contents.append('') # 添加一个空字符串作为消息的一部分 - for i in range(0, len(data), 30): - contents.append(data[i:i + 30]) - contents.append(UpDataTime) - - - for content in contents: - chat_panel.chat_receive_text.AppendText(content+'\n') - def click_find_button(self, event): self.chat_page.Hide() self.connect_page.Hide() @@ -149,20 +130,22 @@ class ChatFrame(wx.Frame,ProcessClient): Contact = data['Contact'] Remark = data['Remark'] Time = data['UpDataTime'] - wx.CallAfter(self.chat_page.ChatPage_add_Contact_person, Contact, Remark) - case 'ChatPage_add_Contact_tab': + state = data['state'] + if state: + wx.CallAfter(self.chat_page.ChatPage_add_Contact_person, Contact, Remark) + case 'Chat_screen_show': Contact = None data = data['content'] - send = data['send'] - receive = data['receive'] + send = data['Send'] + receive = data['Receive'] Type = data['Type'] - content = data['content'] - UpDataTime = data['UpDataTime'] + content = data['Content'] + UpDataTime = data['Time'] if send == str(self.userid): Contact = receive elif receive == str(self.userid): Contact = send - wx.CallAfter(self.send_Chat_history, Contact, send, receive, Type, content, UpDataTime) + wx.CallAfter(self.chat_page.Chat_screen_show, Contact, send, receive, Type, content, UpDataTime) class ChatPage(wx.Panel): def __init__(self, parent): @@ -182,7 +165,7 @@ class ChatFrame(wx.Frame,ProcessClient): def ChatPage_add_Contact_person(self, Id, Remark): contact_page = wx.Panel(self.ChatPage_Listbook) self.ChatPage_Listbook.AddPage(contact_page, Remark) - chat_page = self.ChatPage_add_Contact_tab() + chat_page = self.ChatPage_add_Contact_tab(Id) self.chat_page_map[Id] = chat_page self.chat_page_ids.append(Id) @@ -199,12 +182,15 @@ class ChatFrame(wx.Frame,ProcessClient): # 重新布局 self.Layout() - def ChatPage_add_Contact_tab(self): + def ChatPage_add_Contact_tab(self, Id): chat_panel = wx.Panel(self) chat_box = wx.BoxSizer(wx.VERTICAL) + chat_panel.contact_id = Id + chat_receive_box = wx.BoxSizer(wx.HORIZONTAL) - chat_panel.chat_receive_text = rt.RichTextCtrl(chat_panel, style=wx.TE_MULTILINE | wx.TE_READONLY) + chat_panel.chat_receive_text = rt.RichTextCtrl(chat_panel, + style=wx.VSCROLL | wx.HSCROLL | wx.NO_BORDER | wx.WANTS_CHARS) chat_receive_box.Add(chat_panel.chat_receive_text, 1, wx.EXPAND, 0) chat_box.Add(chat_receive_box, 2, wx.EXPAND, 0) @@ -224,12 +210,60 @@ class ChatFrame(wx.Frame,ProcessClient): chat_box.Add(chat_send_box, 1, wx.EXPAND, 0) send_button = wx.Button(chat_panel, label='发送') # Create a send button + send_button.Bind(wx.EVT_BUTTON, self.on_send_button_click) chat_send_box.Add(send_button, 0, wx.EXPAND | wx.LEFT, 5) # Add the button to the send box chat_panel.SetSizer(chat_box) return chat_panel + def Chat_screen_show(self, Contact, send, receive, Type, data, UpDataTime): + chat_panel = self.chat_page_map[Contact] + if Type == 'text': + # 确定对齐方式 + if Contact == receive: + alignment = wx.TEXT_ALIGNMENT_RIGHT + else: + alignment = wx.TEXT_ALIGNMENT_LEFT + # 开始设置对齐 + chat_panel.chat_receive_text.BeginAlignment(alignment) + # 按每30个字符分割消息内容并写入 + contents = [data[i:i + 30] for i in range(0, len(data), 30)] + contents.append(UpDataTime) # 添加时间戳 + for content in contents: + chat_panel.chat_receive_text.WriteText(content + '\n') # WriteText处理换行 + # 结束对齐设置 + chat_panel.chat_receive_text.EndAlignment() + # 添加额外的新行(如果需要) + chat_panel.chat_receive_text.Newline() + + # 在添加完所有消息后 + chat_panel.chat_receive_text.ShowPosition(chat_panel.chat_receive_text.GetLastPosition()) + chat_panel.Refresh() + chat_panel.Update() + self.Layout() + + def on_send_button_click(self, event): + button = event.GetEventObject() + chat_panel = button.GetParent() + send_text = chat_panel.chat_send_text.GetValue() # 正确获取输入框内容 + contact_id = str(chat_panel.contact_id) # 获取联系人ID + if send_text == '': + return + + self.Chat_screen_show(contact_id, None, contact_id, 'text', send_text, + time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())) + + data = {"Type": "text", "content": send_text} + + content = {"genre": '聊天记录', "target": contact_id, "content": data} + + top_frame = self.GetTopLevelParent() + + top_frame.Process_client_send('Session_server', 'send_server', content) + chat_panel.chat_send_text.SetValue('') # 清空输入框 + event.Skip() + def on_page_changed(self, event): # 获取当前选定的页面的索引 current_page_index = self.ChatPage_Listbook.GetSelection() diff --git a/python/code/chat_room/Chat_Room_Second/Client/Page/Login.py b/python/code/chat_room/Chat_Room_Second/Client/Page/Login.py new file mode 100644 index 0000000..3e7891b --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Client/Page/Login.py @@ -0,0 +1,270 @@ +import json +import multiprocessing +import os + +import wx +import threading +import time +from Client.Transmission.Process_Client import ProcessClient +from .Chat_main import ChatFrame + + +def open_chat_window(Id): + app = wx.App() + ChatFrame(Id).Show() + app.MainLoop() + + +class LoginFrame(wx.Frame, ProcessClient): + def __init__(self): + wx.Frame.__init__(self, None, id=-1, title='登录', pos=wx.DefaultPosition, size=(380, 300)) + ProcessClient.__init__(self) + + current_file_path = __file__ + current_file_name = os.path.basename(current_file_path).split('.')[0] + self.Process_client_send("Server", "Name", current_file_name) + + # 创建菜单栏 + menu_bar = wx.MenuBar() + + # 登录菜单 + login_menu = wx.Menu() + menu_bar.Append(login_menu, "登录") + + # 更多菜单 + more_menu = wx.Menu() + self.register_id = wx.NewId() + self.set_server_id = wx.NewId() + more_menu.Append(self.register_id, "注册账号") + more_menu.Append(self.set_server_id, "服务器设置") + menu_bar.Append(more_menu, "更多") + + self.SetMenuBar(menu_bar) + + # 创建状态栏 + self.status_bar = self.CreateStatusBar(2) + self.server_status = False # 服务器状态 + status_thread = threading.Thread(target=self.update_status_bar(None), daemon=True) + status_thread.start() + + # 启动定时器,每秒钟触发一次 + self.timer = wx.Timer(self) + self.Bind(wx.EVT_TIMER, self.update_status_bar, self.timer) + self.timer.Start(1000) # 设置定时器间隔为1000毫秒(1秒 + + # 获取菜单点击事件 + self.Bind(wx.EVT_MENU, self.click_menu, id=self.register_id) + self.Bind(wx.EVT_MENU, self.click_menu, id=self.set_server_id) + self.Bind(wx.EVT_MENU_OPEN, self.click_menu_title) + + # 创建注册面板 + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.login_panel = LoginPanel(self) + self.register_panel = RegisterPanel(self) + self.sizer.Add(self.login_panel, 1, wx.EXPAND) + self.sizer.Add(self.register_panel, 1, wx.EXPAND) + + self.login_panel.Hide() + self.register_panel.Hide() + + self.login_panel.Show() + + # 主页按钮绑定 + self.Bind(wx.EVT_BUTTON, self.send_login_button, self.login_panel.LoginPanel_login_label) + self.Bind(wx.EVT_BUTTON, self.send_register_button, self.register_panel.RegisterPanel_login_label) + + self.SetSizer(self.sizer) + + def update_status_bar(self, event): + if self.server_status: + self.status_bar.SetStatusText("服务器\t已连接", 0) + else: + self.status_bar.SetStatusText("服务器\t未连接", 0) + + self.status_bar.SetStatusText("时间\t" + time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()), 1) + + def click_menu_title(self, event): + menu = event.GetMenu() + menu_title = menu.GetTitle() + if menu_title == "登录": + self.login_panel.Hide() + self.register_panel.Hide() + self.login_panel.Show() + self.Layout() + + # 点击菜单检测 + def click_menu(self, event): + menu_id = event.GetId() + if menu_id == self.register_id: + self.login_panel.Hide() + self.register_panel.Hide() + self.register_panel.Show() + self.Layout() + elif menu_id == self.set_server_id: + self.login_panel.Hide() + self.register_panel.Hide() + self.Layout() + + def login_page_receive(self, receive_content): + if receive_content["genre"] == '登录': + match receive_content["data"]['status']: + case 0: + self.Process_client_send("File_operate", "detection_data", receive_content["data"]['account']) + wx.MessageBox('登录成功正在获取数据', '登录', wx.OK | wx.ICON_INFORMATION) + case -1: + wx.MessageBox('重复登录', '登录', wx.OK | wx.ICON_INFORMATION) + case 1: + wx.MessageBox('密码错误', '登录', wx.OK | wx.ICON_INFORMATION) + case 2: + wx.MessageBox('未找到该账号', '登录', wx.OK | wx.ICON_INFORMATION) + elif receive_content["genre"] == '注册': + wx.MessageBox( + f'注册成功\n网名 : {receive_content["data"]['NetName']} \n账号 : {receive_content["data"]['Id']} \n密码 : {receive_content["data"]['Password']}', + '注册', wx.OK | wx.ICON_INFORMATION) + + def send_login_button(self, event): + if self.server_status: + account = self.login_panel.LoginPanel_account_text.GetValue().strip() + password = self.login_panel.LoginPanel_password_text.GetValue().strip() + content = {'account': account, 'password': password} + target = "服务器" + genre = "登录" + data = {"genre": genre, "target": target, "content": content} + if account and password: + self.Process_client_send("Session_server", "send_server", data) + + + def send_register_button(self, event): + if self.server_status: + account = self.register_panel.RegisterPanel_account_text.GetValue().strip() + password = self.register_panel.RegisterPanel_password_text.GetValue().strip() + content = {'account': account, 'password': password} + target = "服务器" + genre = "注册" + data = {"genre": genre, "target": target, "content": content} + if account and password: + self.Process_client_send("Session_server", "send_server", data) + + + def Process_client_pick(self, data): + if data['target'] in ['ALL', 'Login']: + match data['function']: + case 'server_status': + self.server_status = data['content'] + case 'login_page_receive': + self.login_page_receive(data['content']) + case '更新完成': + multiprocessing.Process(target=open_chat_window, args=(data['content'],)).start() + self.Destroy() + + + +class LoginPanel(wx.Panel): + def __init__(self, parent): + super().__init__(parent) + # 主盒子 + LoginPanel_main_box = wx.BoxSizer(wx.VERTICAL) + + # 顶部盒子,目前只放了软件名 + LoginPanel_top_box = wx.BoxSizer(wx.VERTICAL) # 使用垂直盒子 + LoginPanel_show_title = wx.StaticText(self, label='登录') + LoginPanel_show_title.SetFont(wx.Font(30, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + LoginPanel_top_box.Add(LoginPanel_show_title, 1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 10) + LoginPanel_main_box.Add(LoginPanel_top_box, 0, wx.EXPAND) + + # 中部盒子,放账号和密码 + LoginPanel_content_box = wx.BoxSizer(wx.VERTICAL) + # 账号 + LoginPanel_account_box = wx.BoxSizer(wx.HORIZONTAL) + LoginPanel_account_label = wx.StaticText(self, label=' 账号:') + LoginPanel_account_label.SetFont( + wx.Font(15, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + LoginPanel_account_box.Add(LoginPanel_account_label, 0, wx.ALIGN_CENTER_VERTICAL) + self.LoginPanel_account_text = wx.TextCtrl(self, size=(300, 30)) + self.LoginPanel_account_text.SetHint('请输入账号') + LoginPanel_account_box.Add(self.LoginPanel_account_text, 1, wx.ALIGN_CENTER_VERTICAL) + LoginPanel_content_box.Add(LoginPanel_account_box) + # 添加空白控件来增加间距 + LoginPanel_content_box.Add(wx.StaticText(self, label=''), 0, wx.ALL, 5) + # 密码 + LoginPanel_password_box = wx.BoxSizer(wx.HORIZONTAL) + LoginPanel_password_label = wx.StaticText(self, label=' 密码:') + LoginPanel_password_label.SetFont( + wx.Font(15, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + LoginPanel_password_box.Add(LoginPanel_password_label, 0, wx.ALIGN_CENTER_VERTICAL) + self.LoginPanel_password_text = wx.TextCtrl(self, size=(300, 30)) + self.LoginPanel_password_text.SetHint('请输入密码') + LoginPanel_password_box.Add(self.LoginPanel_password_text, 1, wx.ALIGN_CENTER_VERTICAL) + LoginPanel_content_box.Add(LoginPanel_password_box) + LoginPanel_main_box.Add(LoginPanel_content_box, 0, wx.EXPAND) + + # 底部盒子 + LoginPanel_bottom_box = wx.BoxSizer(wx.VERTICAL) + # 登录按钮 + LoginPanel_login_box = wx.BoxSizer(wx.VERTICAL) # 使用垂直盒子布局 + self.LoginPanel_login_label = wx.Button(self, size=(200, 50), label='登录') + LoginPanel_login_box.AddStretchSpacer() # 添加一个可伸缩的空间,将登录按钮推到垂直中间 + LoginPanel_login_box.Add(self.LoginPanel_login_label, 0, wx.ALIGN_CENTER_HORIZONTAL) # 将登录按钮添加到垂直盒子中 + LoginPanel_login_box.AddStretchSpacer() # 再次添加一个可伸缩的空间,将登录按钮推到垂直中间 + LoginPanel_bottom_box.Add(LoginPanel_login_box, 1, + wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL) # 将垂直盒子添加到底部盒子中,设置垂直和水平居中对齐 + LoginPanel_main_box.Add(LoginPanel_bottom_box, 1, wx.EXPAND) # 将底部盒子添加到主盒子中,使其填满剩余空间 + + self.SetSizer(LoginPanel_main_box) + + +class RegisterPanel(wx.Panel): + def __init__(self, parent): + super().__init__(parent) + + # 主盒子 + RegisterPanel_main_box = wx.BoxSizer(wx.VERTICAL) + + # 顶部盒子,目前只放了软件名 + RegisterPanel_top_box = wx.BoxSizer(wx.VERTICAL) # 使用垂直盒子 + RegisterPanel_show_title = wx.StaticText(self, label='注册') + RegisterPanel_show_title.SetFont( + wx.Font(30, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + RegisterPanel_top_box.Add(RegisterPanel_show_title, 1, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 10) + RegisterPanel_main_box.Add(RegisterPanel_top_box, 0, wx.EXPAND) + + # 中部盒子,放账号和密码 + RegisterPanel_content_box = wx.BoxSizer(wx.VERTICAL) + # 账号 + RegisterPanel_account_box = wx.BoxSizer(wx.HORIZONTAL) + RegisterPanel_account_label = wx.StaticText(self, label=' 用户名:') + RegisterPanel_account_label.SetFont( + wx.Font(15, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + RegisterPanel_account_box.Add(RegisterPanel_account_label, 0, wx.ALIGN_CENTER_VERTICAL) + self.RegisterPanel_account_text = wx.TextCtrl(self, size=(300, 30)) + self.RegisterPanel_account_text.SetHint('请输入用户名') + RegisterPanel_account_box.Add(self.RegisterPanel_account_text, 1, wx.ALIGN_CENTER_VERTICAL) + RegisterPanel_content_box.Add(RegisterPanel_account_box) + # 添加空白控件来增加间距 + RegisterPanel_content_box.Add(wx.StaticText(self, label=''), 0, wx.ALL, 5) + # 密码 + RegisterPanel_password_box = wx.BoxSizer(wx.HORIZONTAL) + RegisterPanel_password_label = wx.StaticText(self, label=' 密码: ') + RegisterPanel_password_label.SetFont( + wx.Font(15, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) + RegisterPanel_password_box.Add(RegisterPanel_password_label, 0, wx.ALIGN_CENTER_VERTICAL) + self.RegisterPanel_password_text = wx.TextCtrl(self, size=(300, 30)) + self.RegisterPanel_password_text.SetHint('请输入密码') + RegisterPanel_password_box.Add(self.RegisterPanel_password_text, 1, wx.ALIGN_CENTER_VERTICAL) + RegisterPanel_content_box.Add(RegisterPanel_password_box) + RegisterPanel_main_box.Add(RegisterPanel_content_box, 0, wx.EXPAND) + + # 底部盒子 + RegisterPanel_bottom_box = wx.BoxSizer(wx.VERTICAL) + # 登录按钮 + RegisterPanel_register_box = wx.BoxSizer(wx.VERTICAL) # 使用垂直盒子布局 + self.RegisterPanel_login_label = wx.Button(self, size=(200, 50), label='确认') + RegisterPanel_register_box.AddStretchSpacer() # 添加一个可伸缩的空间,将登录按钮推到垂直中间 + RegisterPanel_register_box.Add(self.RegisterPanel_login_label, 0, + wx.ALIGN_CENTER_HORIZONTAL) # 将登录按钮添加到垂直盒子中 + RegisterPanel_register_box.AddStretchSpacer() # 再次添加一个可伸缩的空间,将登录按钮推到垂直中间 + RegisterPanel_bottom_box.Add(RegisterPanel_register_box, 1, + wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL) # 将垂直盒子添加到底部盒子中,设置垂直和水平居中对齐 + RegisterPanel_main_box.Add(RegisterPanel_bottom_box, 1, wx.EXPAND) # 将底部盒子添加到主盒子中,使其填满剩余空间 + + self.SetSizer(RegisterPanel_main_box) diff --git a/python/code/chat_room/Chat_Room_Second/Client/Page/__init__.py b/python/code/chat_room/Chat_Room_Second/Client/Page/__init__.py new file mode 100644 index 0000000..a4f53a0 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Client/Page/__init__.py @@ -0,0 +1,2 @@ +from .Chat_main import * +from .Login import * diff --git a/python/code/chat_room/Chat_Room_Second/Client/Transmission/File_operate.py b/python/code/chat_room/Chat_Room_Second/Client/Transmission/File_operate.py new file mode 100644 index 0000000..311bc34 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Client/Transmission/File_operate.py @@ -0,0 +1,103 @@ +import os +import csv +import time + +from .Process_Client import ProcessClient + + +class FileOperate(ProcessClient): + def __init__(self, user_id): + ProcessClient.__init__(self) + + self.user_id = user_id + + self.root_path = None + self.Account_path = None + self.Contacts_path = None + self.History_path = None + self.file_root_path = None + self.other_file_path = None + self.image_file_path = None + + current_file_path = __file__ + current_file_name = os.path.basename(current_file_path).split('.')[0] + self.Process_client_send("Server", "Name", current_file_name) + + def detection_data(self, Id): + self.user_id = Id + self.root_path = rf'.\{Id}' + self.Account_path = self.root_path + r'\Account.csv' + self.Contacts_path = self.root_path + r'\Contacts.csv' + self.History_path = self.root_path + r'\History.csv' + self.file_root_path = self.root_path + r'\file' + self.other_file_path = self.file_root_path + r'\other' + self.image_file_path = self.file_root_path + r'\image' + if not os.path.isdir(self.root_path): + os.mkdir(self.root_path) + if not os.path.isdir(self.file_root_path): + os.mkdir(self.file_root_path) + os.mkdir(self.other_file_path) + os.mkdir(self.image_file_path) + if not os.path.exists(self.Account_path): + with open(self.Account_path, 'w', encoding='utf-8') as f: + pass + with open(self.Account_path, 'r+', encoding='utf-8') as info: + data = csv.DictReader(info) + if os.path.getsize(self.Account_path) == 0: # 检查文件大小是否为0 + date = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(0)) + else: + for d in data: + date = d['UpDataTime'] + + target = "服务器" + genre = "数据更新" + data = {"genre": genre, "target": target, "content": date} + self.Process_client_send("Session_server", "send_server", data) + + def read_data(self): + with open(self.Contacts_path, 'r', encoding='utf-8') as Contacts: + data = csv.reader(Contacts) + next(data) + for i in data: + content = {'Contact': i[0], 'Remark': i[1], 'state': i[2], 'UpDataTime': i[3]} + self.Process_client_send("Chat_main", "ChatPage_add_Contact_person", content) + with open(self.History_path, 'r', encoding='utf-8') as History_path: + data = csv.reader(History_path) + next(data) + for i in data: + content = {'Send': i[0], 'Receive': i[1], 'Type': i[2], 'Content': i[3], 'Time': i[4]} + self.Process_client_send("Chat_main", "Chat_screen_show", content) + + def save_data(self, data): + target = list(data.keys())[0] + data = list(data.values())[0] + match target: + case 'Account': + with open(self.Account_path, 'w+', encoding='utf-8', newline='') as file: + csv_file = csv.writer(file) + csv_file.writerow(list(data.keys())) + csv_file.writerow(list(data.values())) + case 'Contacts': + with open(self.Contacts_path, 'a+', encoding='utf-8', newline='') as file: + csv_file = csv.writer(file) + if os.path.getsize(self.Contacts_path) == 0: # 检查文件大小是否为0 + csv_file.writerow(list(data.keys())) + csv_file.writerow(list(data.values())) + case 'History': + with open(self.History_path, 'a+', encoding='utf-8', newline='') as file: + csv_file = csv.writer(file) + if os.path.getsize(self.History_path) == 0: # 检查文件大小是否为0 + csv_file.writerow(list(data.keys())) + csv_file.writerow(list(data.values())) + case '更新完成': + self.Process_client_send("ALL", "更新完成", eval(data)) + + def Process_client_pick(self, data): + if data['target'] in ['ALL', 'File_operate']: + match data['function']: + case 'detection_data': + self.detection_data(data['content']) + case 'save_data': + self.save_data(data['content']) + case 'read_data': + self.read_data() diff --git a/python/code/chat_room/Chat_Room_Second/Client/Transmission/Process_Client.py b/python/code/chat_room/Chat_Room_Second/Client/Transmission/Process_Client.py new file mode 100644 index 0000000..f7dcc60 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Client/Transmission/Process_Client.py @@ -0,0 +1,31 @@ +import json +import threading +from multiprocessing.connection import Client + + +class ProcessClient: + def __init__(self): + self.Process_port = 8727 + self.Process_server = 'localhost' + self.Process_client_Client = Client((self.Process_server, self.Process_port)) + Process_client_recv = threading.Thread(target=self.Process_client_recv) + Process_client_recv.start() + + def Process_client_send(self, target, function, content): + data = {"target": target, "function": function, "content": content} + data_json = json.dumps(data) + self.Process_client_Client.send(data_json) + + def Process_client_recv(self): + while True: + try: + data_json = self.Process_client_Client.recv() + data = json.loads(data_json) + self.Process_client_pick(data) + + except ConnectionResetError as e: + print("连接已关闭: " + str(e)) + break + + def Process_client_pick(self, data): + pass diff --git a/python/code/chat_room/Chat_Room_Second/Client/Transmission/Process_Server.py b/python/code/chat_room/Chat_Room_Second/Client/Transmission/Process_Server.py new file mode 100644 index 0000000..5221a68 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Client/Transmission/Process_Server.py @@ -0,0 +1,52 @@ +import json +import multiprocessing +from multiprocessing.connection import Listener +import threading + + +class ProcessServer: + def __init__(self): + try: + self.Process_port = 8727 + self.Process_server = 'localhost' + self.Process_server_listener = Listener((self.Process_server, self.Process_port)) + self.Process_client_link_dick = {} + Process_client_link_Thread = threading.Thread(target=self.Process_client_link) + Process_client_link_Thread.start() + except: + print("进程通信端口绑定失败") + + def Process_client_link(self): + while True: + client_connect = self.Process_server_listener.accept() + client_Thread_recv = threading.Thread(target=self.Process_client_recv, args=(client_connect,)) + client_Thread_recv.start() + + def Process_client_recv(self, client_Thread_recv): + while True: + try: + data_json = client_Thread_recv.recv() + data = json.loads(data_json) + if data['target'] == 'Server': + if data['function'] == 'Name': + self.Process_client_link_dick[data['content']] = client_Thread_recv + else: + self.Process_client_pick(data) + except ConnectionResetError as e: + print("进程关闭" + str(e)) + + def Process_client_send(self, target, function, content): + connect = self.Process_client_link_dick[target] + data = {"target": target, "function": function, "content": content} + data_json = json.dumps(data) + connect.send(data_json) + + def Process_client_pick(self, data): + if data['target'] == 'ALL': + for value in self.Process_client_link_dick.values(): + data_json = json.dumps(data) + value.send(data_json) + else: + if data['target'] in self.Process_client_link_dick.keys(): + data_json = json.dumps(data) + self.Process_client_link_dick[data['target']].send(data_json) diff --git a/python/code/chat_room/Chat_Room_Second/Client/Transmission/Session_server.py b/python/code/chat_room/Chat_Room_Second/Client/Transmission/Session_server.py new file mode 100644 index 0000000..ff833f0 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Client/Transmission/Session_server.py @@ -0,0 +1,85 @@ +import multiprocessing +import os +import time +import socket +import json +import threading +from .Process_Client import ProcessClient + + +class Session_server(ProcessClient): + def __init__(self): + ProcessClient.__init__(self) + self.socker_ip = "127.0.0.1" + self.socker_port = 7868 + self.server_socket = None + self.server_status = False # 服务器状态 + self.link_server_Thread = threading.Thread(target=self.link_server) + self.link_server_Thread.start() + self.receive_server_Thread = threading.Thread(target=self.receive_server) + + current_file_path = __file__ + current_file_name = os.path.basename(current_file_path).split('.')[0] + self.Process_client_send("Server", "Name", current_file_name) + + def link_server(self): + while True: + if not self.server_status: + time.sleep(1) + if self.server_socket is not None: + self.server_socket = None + try: + self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.server_socket.connect((self.socker_ip, self.socker_port)) + self.server_status = True + if not self.receive_server_Thread.is_alive(): + self.receive_server_Thread.start() + except Exception as a: + self.server_status = False + print("连接错误:" + str(a)) + finally: + self.Process_client_send("ALL", "server_status", self.server_status) + pass + + def receive_server(self): + while self.server_status: + try: + receive_content_json = self.server_socket.recv(1024).decode('utf-8') + receive_content = json.loads(receive_content_json) + self.content_pick(receive_content) + except Exception as a: + print("客户端接收错误:" + str(a)) + self.server_status = False + self.Process_client_send("ALL", "server_status", self.server_status) + + def send_server(self, genre, target, content): + if self.server_status: + try: + data = {"genre": genre, "target": target, "data": content, + "datetime": time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())} + data_json = json.dumps(data) + '\n' + self.server_socket.send(data_json.encode("utf-8")) + except Exception as a: + print("发送错误:" + str(a)) + self.server_status = False + self.Process_client_send("ALL", "server_status", self.server_status) + + def Process_client_pick(self, data): + if data['target'] in ['ALL', 'Session_server']: + match data['function']: + case 'server_status': + self.server_status = data['content'] + case 'send_server': + self.send_server(data['content']['genre'], data['content']['target'], data['content']['content']) + + def content_pick(self, data): + match data['genre']: + case '注册' | '登录': + self.Process_client_send("Login", "login_page_receive", data) + case '数据更新': + self.Process_client_send("File_operate", "save_data", data['data']) + case '聊天记录': + if data['data']['Type'] == 'text': + self.Process_client_send("File_operate", "save_data", {"History": data['data']}) + if data['target'] == '接收': + self.Process_client_send("Chat_main", "Chat_screen_show", data['data']) diff --git a/python/code/chat_room/Chat_Room_Second/Client/Transmission/__init__.py b/python/code/chat_room/Chat_Room_Second/Client/Transmission/__init__.py new file mode 100644 index 0000000..7f42f08 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Client/Transmission/__init__.py @@ -0,0 +1,4 @@ +from .Process_Server import * +from .Process_Client import * +from .Session_server import * +from .File_operate import * \ No newline at end of file diff --git a/python/code/chat_room/Chat_Room_Second/Client/__init__.py b/python/code/chat_room/Chat_Room_Second/Client/__init__.py new file mode 100644 index 0000000..38abfd7 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Client/__init__.py @@ -0,0 +1,16 @@ +from .Page import * +from .Transmission import * + + +class start_all: + def __init__(self): + ProcessServer() + + Session_server() + + FileOperate(None) + + app = wx.App() + LoginFrame().Show() + app.MainLoop() + diff --git a/python/code/chat_room/Chat_Room_Second/Client/image/chat.png b/python/code/chat_room/Chat_Room_Second/Client/image/chat.png new file mode 100644 index 0000000000000000000000000000000000000000..9b6bcb86ce647c2ae2b3cfefa44ea6fd792d18ca GIT binary patch literal 2871 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 literal 0 HcmV?d00001 diff --git a/python/code/chat_room/Chat_Room_Second/Client/image/file.png b/python/code/chat_room/Chat_Room_Second/Client/image/file.png new file mode 100644 index 0000000000000000000000000000000000000000..382d79145e35831bbfd79d37a85cb66079a4b2fa GIT binary patch literal 23101 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

irgnbs10I!1^Upw!R4e3L&Ax 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 Zu%&r%MAxT*AoM|#_L2|mqMIL${trPD;$8p% literal 0 HcmV?d00001 diff --git a/python/code/chat_room/Chat_Room_Second/Client/image/find.png b/python/code/chat_room/Chat_Room_Second/Client/image/find.png new file mode 100644 index 0000000000000000000000000000000000000000..dbbf0108ef0e2113254d8aa6d179508169a23d69 GIT binary patch literal 1347 zcmV-J1-$x+P)Px({YgYYR9Hvtm|ch)RTRh1oy?u@$=7CUOx z?aXZ1ut@J??m74T^1t_<{BIDf@PSr1A6x~z(jEHWDu~ME^7WQwZE#(;!t;ENWm(ki zb}w=q_meEk-_&X~<4V<|`H2;*R4Q51G>p>9QHeWOVfHuQ04k3gggh&9O0ssR5Ah=1}QXyjl zmP(~ZbX|Xw5R#$Fvn+c~6vfB7-L8%h@+lM{gcC(^z2i8qg<+Vb>LG-t%jNQ>YPEWP zDUh)MbGh6twrw8^!*Gl$CW_)=j^m!!b-nX%Mf3Umb+&E4-Rt%40{|=t!Y6_t?3|sQ zwUR={0+eO>1K;-_27o{igcm!V4n13!9ocL)>p0GPVHj?q3KxsT9n;g(pGM^^o{t2~ z=ksaHvVJFo@Cc#vilW@rY&P3*3XP48-83^Z^CJN8JkOhjLgCsA7cRJQa{DonfSF9@ zux;DB0bs6BDBP`S+Sw!pR8>9Xy6&SiC!J1jGz{bOB>7Q*0>+pE-OMnI=6T)-0Q8a+ zD3{A)nx_3iFOeik&$L>t{Ymnp0Mi)b?*L#NV|>oG?TI9d_haeyhGCfDdH#T9Sx+We zBMLBsF+M{9IgUHq?RM8CS-c-B2*PZy*DHvk_*T2!-kW5NC_o8g{5=4yWf-RBd0v?| z;3Ne`Mn+1FMq`FHa-Qe+S(f!ulKdz@B+K$~-}fH`0B>}3^u}tn`dg9$s;a)~y6)5S zmt>n^7{`<3M*%{ySX^ru#t*brh@$v~D2iJfjYc<4k!&_QYTNb{A!LYUSv{A_t*O`R zdYs(YZH5NQvV79_{rdsHktFGfR;zU=MiEw)<%7QO@1n;-RnwXr7;czOI(m9UXmCxr-{a4dfRdom<^tj_V`{>!j7@z+0EN^bN+s$PG1OQG^ zls%s39hi42KF0V%Q526=DwUH{Q&ToAJU%{N(ll+`+}zwlK@i+SKTD-jEm0IVU%GVZ z+oW(bK9++0g@=ZQc3GCSKMccb`nd=pmtmNT2q8WQf?)t)7lN!>wd&qlt#)cDaESq_ zdaA142>`o2&)d1kto9lD2KBEm&$8_4)vH%;saC7AOMy(J;KBl>QfZ{q=}!^5|lrb+G95G9f%>A86~ z6Wb9jD*Zs2B>y1zqecvCYPua^s4iu28s3^*I-}fJoB literal 0 HcmV?d00001 diff --git a/python/code/chat_room/Chat_Room_Second/Client/image/picture.png b/python/code/chat_room/Chat_Room_Second/Client/image/picture.png new file mode 100644 index 0000000000000000000000000000000000000000..42aa5cb35f1ec8a21aabf0bff8dc0efd4da8d714 GIT binary patch literal 18674 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 DhXo$0 literal 0 HcmV?d00001 diff --git a/python/code/chat_room/Chat_Room_Second/Client/image/speech.png b/python/code/chat_room/Chat_Room_Second/Client/image/speech.png new file mode 100644 index 0000000000000000000000000000000000000000..4bbe387006b4b269a0454cc98f80f878644a5ef5 GIT binary patch literal 21178 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 literal 0 HcmV?d00001 diff --git a/python/code/chat_room/Chat_Room_Second/Client/image/video.png b/python/code/chat_room/Chat_Room_Second/Client/image/video.png new file mode 100644 index 0000000000000000000000000000000000000000..076fc193dc65ddfda4c2036e350570a5042f363d GIT binary patch literal 7236 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 '{date}'") + Contacts_database = self.database_cursor.fetchall() + for Contact in Contacts_database: + Contacts_content = {'Contact': Contact[0], + 'Remark': Contact[1], + 'State': Contact[2], + 'UpDataTime': Contact[3].strftime('%Y-%m-%d %H:%M:%S')} + Contacts_data = {"Contacts": Contacts_content} + datas.append(Contacts_data) + + self.database_cursor.execute(f"select * from History where Send = {Id} or Receive = {Id} and Time > '{date}'") + History_database = self.database_cursor.fetchall() + for History in History_database: + content = { + 'Send': History[0], + 'Receive': History[1], + 'Type': History[2], + 'Content': History[3], + 'Time': History[4].strftime('%Y-%m-%d %H:%M:%S')} + History_data = {"History": content} + datas.append(History_data) + + datas.append({"更新完成": Id}) + + for data in datas: + time.sleep(0.1) + content = {"client_id": Id, "target": "客户端", "genre": "数据更新", "data": data} + self.Process_client_send('Session_client', 'send_client', content) + + def update_History(self, Send, Receive, Type, Content, Time): + if self.database_state: + try: + self.database_cursor.execute(f"insert into History(Send, Receive, Type, Content,Time)" + f"select {Send},{Receive},'{Type}',N'{Content}','{Time}'") + self.database_conn.commit() + except pymssql as a: + self.database_state = False + print(a) + + def Process_client_pick(self, data): + if data['target'] in ['ALL', 'Database_formula']: + match data['function']: + case 'check_account_state': + + self.check_account_state(data['content']['client_id'], + data['content']['account'], + data['content']['password']) + + case 'sign_account': + + self.sign_account(data['content']['client_id'], + data['content']['account'], + data['content']['password']) + + case 'alter_state_database': + self.alter_state_database(data['content']['Id'], + data['content']['sate']) + + case 'detection_data': + self.detection_data(data['content']['client_id'], + data['content']['date']) + + case 'update_History': + self.update_History(data['content']['Send'], + data['content']['Receive'], + data['content']['Type'], + data['content']['Content'], + data['content']['Time']) diff --git a/python/code/chat_room/Chat_Room_Second/Server/Transmission/Process_Client.py b/python/code/chat_room/Chat_Room_Second/Server/Transmission/Process_Client.py new file mode 100644 index 0000000..4938987 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Server/Transmission/Process_Client.py @@ -0,0 +1,30 @@ +import json +import threading +from multiprocessing.connection import Client + + +class ProcessClient: + def __init__(self): + self.Process_port = 3244 + self.Process_server = 'localhost' + self.Process_client_Client = Client((self.Process_server, self.Process_port)) + Process_client_recv = threading.Thread(target=self.Process_client_recv) + Process_client_recv.start() + + def Process_client_send(self, target, function, content): + data = {"target": target, "function": function, "content": content} + data_json = json.dumps(data) + self.Process_client_Client.send(data_json) + + def Process_client_recv(self): + while True: + try: + data_json = self.Process_client_Client.recv() + data = json.loads(data_json) + self.Process_client_pick(data) + except EOFError: + print("连接已关闭") + break + + def Process_client_pick(self, data): + pass diff --git a/python/code/chat_room/Chat_Room_Second/Server/Transmission/Process_Server.py b/python/code/chat_room/Chat_Room_Second/Server/Transmission/Process_Server.py new file mode 100644 index 0000000..8ff2369 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Server/Transmission/Process_Server.py @@ -0,0 +1,49 @@ +import json +import multiprocessing +from multiprocessing.connection import Listener +import threading + + +class ProcessServer: + def __init__(self): + try: + self.Process_port = 3244 + self.Process_server = 'localhost' + self.Process_server_listener = Listener((self.Process_server, self.Process_port)) + self.Process_client_link_dick = {} + Process_client_link_Thread = threading.Thread(target=self.Process_client_link) + Process_client_link_Thread.start() + except: + print("进程通信端口绑定失败") + + def Process_client_link(self): + while True: + client_connect = self.Process_server_listener.accept() + client_Thread_recv = threading.Thread(target=self.Process_client_recv, args=(client_connect,)) + client_Thread_recv.start() + + def Process_client_recv(self, client_Thread_recv): + while True: + data_json = client_Thread_recv.recv() + data = json.loads(data_json) + if data['target'] == 'Server': + if data['function'] == 'Name': + self.Process_client_link_dick[data['content']] = client_Thread_recv + else: + self.Process_client_pick(data) + + def Process_client_send(self, target, function, content): + connect = self.Process_client_link_dick[target] + data = {"target": target, "function": function, "content": content} + data_json = json.dumps(data) + connect.send(data_json) + + def Process_client_pick(self, data): + if data['target'] == 'ALL': + for value in self.Process_client_link_dick.values(): + data_json = json.dumps(data) + value.send(data_json) + else: + if data['target'] in self.Process_client_link_dick.keys(): + data_json = json.dumps(data) + self.Process_client_link_dick[data['target']].send(data_json) diff --git a/python/code/chat_room/Chat_Room_Second/Server/Transmission/Session_client.py b/python/code/chat_room/Chat_Room_Second/Server/Transmission/Session_client.py new file mode 100644 index 0000000..cc36d89 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Server/Transmission/Session_client.py @@ -0,0 +1,127 @@ +import os +import random +import string +import time +import socket +import json +import threading +from .Process_Client import * + + +class link_client(ProcessClient): + def __init__(self): + ProcessClient.__init__(self) + self.server_host = "127.0.0.1" + self.server_port = 7868 + self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.server_socket.bind((self.server_host, self.server_port)) + self.server_socket.listen() + self.client_socket_dict = {} + self.client_max_id = 0 + + current_file_path = __file__ + current_file_name = os.path.basename(current_file_path).split('.')[0] + self.Process_client_send("Server", "Name", current_file_name) + + self.link_client_Thread = threading.Thread(target=self.link_client) + self.link_client_Thread.start() + + def link_client(self): + while True: + try: + client_socket, client_address = self.server_socket.accept() + self.client_max_id += 1 + client_id = ''.join(random.choice(string.ascii_letters) for _ in range(10)) + str(self.client_max_id) + self.client_socket_dict[client_id] = client_socket + recv_client_Thread = threading.Thread(target=self.recv_client, args=(client_socket,), daemon=True) + recv_client_Thread.start() + except: + pass + + def send_client(self, client_id, genre, target, content): + client_socket = self.client_socket_dict[client_id] + try: + data = {"genre": genre, "target": target, "data": content, + "datetime": time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())} + data_json = json.dumps(data) + '\n' + client_socket.send(data_json.encode("utf-8")) + except: + client_socket.close() + + def pick_data(self, client_id, data): + match data['genre']: + case '登录': + content = {'client_id': client_id, 'account': data['data']['account'], + 'password': data['data']['password']} + self.Process_client_send("Database_formula", "check_account_state", content) + case '注册': + content = {'client_id': client_id, 'account': data['data']['account'], + 'password': data['data']['password']} + self.Process_client_send("Database_formula", "sign_account", content) + case '数据更新': + content = {'client_id': client_id, 'date': data['data']} + self.Process_client_send("Database_formula", "detection_data", content) + case '聊天记录': + Send = client_id + Receive = data['target'] + Time = data['datetime'] + data = data['data'] + Type = data['Type'] + Content = data['content'] + content = {'Send': Send, 'Receive': Receive, 'Time': Time, 'Type': Type, 'Content': Content} + self.Process_client_send("Database_formula", "update_History", content) + self.send_client(Send, "聊天记录", "发送", content) + if Receive in self.client_socket_dict: + self.send_client(Receive, "聊天记录", "接收", content) + + def recv_client(self, client_socket): + state = True + while state: + try: + data_json = client_socket.recv(1024).decode('utf-8') + data = json.loads(data_json) + client_Id = self.find_client(client_socket, None) + self.pick_data(client_Id, data) + except: + try: + client_socket.close() + finally: + state = False + self.find_client(client_socket, None) + client_id = self.find_client(client_socket, None) + del self.client_socket_dict[client_id] + if client_id.isdigit(): + self.Process_client_send("Database_formula", "alter_state_database", + {"Id": client_id, "sate": 0}) + + def Process_client_pick(self, data): + if data['target'] in ['ALL', 'Session_client']: + match data['function']: + case 'send_client': + client_id = data['content']['client_id'] + genre = data['content']['genre'] + target = data['content']['target'] + content = data['content']['data'] + if data['content']['genre'] == '登录': + if content['account'] not in self.client_socket_dict: + if content['status'] == 0: + client_socket = self.find_client(None, client_id) + del self.client_socket_dict[client_id] + client_id = content['account'] + self.client_socket_dict[client_id] = client_socket + if client_id.isdigit(): + self.Process_client_send("Database_formula", "alter_state_database", + {"Id": client_id, "sate": 1}) + else: + return + self.send_client(client_id, genre, target, content) + + def find_client(self, client_socket, client_id): + if client_id is None: + for key, value in self.client_socket_dict.items(): + if value == client_socket: + return key + elif client_socket is None: + for key, value in self.client_socket_dict.items(): + if key == client_id: + return value diff --git a/python/code/chat_room/Chat_Room_Second/Server/Transmission/__init__.py b/python/code/chat_room/Chat_Room_Second/Server/Transmission/__init__.py new file mode 100644 index 0000000..1e3f2fb --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Server/Transmission/__init__.py @@ -0,0 +1,4 @@ +from .Process_Server import * +from .Process_Client import * +from .Session_client import * +from .Database_formula import * diff --git a/python/code/chat_room/Chat_Room_Second/Server/__init__.py b/python/code/chat_room/Chat_Room_Second/Server/__init__.py new file mode 100644 index 0000000..21e5173 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/Server/__init__.py @@ -0,0 +1,11 @@ +from .Transmission import * + + +class Server_main: + def __init__(self): + ProcessServer() + database() + link_client() + + + diff --git a/python/code/chat_room/Chat_Room_Second/StartClient.py b/python/code/chat_room/Chat_Room_Second/StartClient.py new file mode 100644 index 0000000..18a9d80 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/StartClient.py @@ -0,0 +1,4 @@ +from Client import start_all + +if __name__ == '__main__': + start_all() diff --git a/python/code/chat_room/Chat_Room_Second/StartServer.py b/python/code/chat_room/Chat_Room_Second/StartServer.py new file mode 100644 index 0000000..8f05cdb --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/StartServer.py @@ -0,0 +1,4 @@ +from Server import Server_main + +if __name__ == '__main__': + Server_main() diff --git a/python/code/chat_room/Chat_Room_Second/start_all.py b/python/code/chat_room/Chat_Room_Second/start_all.py new file mode 100644 index 0000000..a912f00 --- /dev/null +++ b/python/code/chat_room/Chat_Room_Second/start_all.py @@ -0,0 +1,6 @@ +from Client import start_all +from Server import Server_main + +if __name__ == '__main__': + Server_main() + start_all() \ No newline at end of file diff --git a/python/test/test2.py b/python/test/test2.py deleted file mode 100644 index 6e816b9..0000000 --- a/python/test/test2.py +++ /dev/null @@ -1,30 +0,0 @@ -import wx -import wx.richtext as rt - - -class MyFrame(wx.Frame): - def __init__(self, parent, id, title): - wx.Frame.__init__(self, parent, id, title, size=(400, 300)) - panel = wx.Panel(self) - vbox = wx.BoxSizer(wx.VERTICAL) - - # 创建 RichTextCtrl - self.rtc = rt.RichTextCtrl(panel, style=wx.VSCROLL | wx.HSCROLL | wx.NO_BORDER | wx.WANTS_CHARS) - self.rtc.BeginFontSize(12) - self.rtc.WriteText("Here is some text, and here is an image: ") - self.rtc.EndFontSize() - - # 插入图片 - image = wx.Bitmap('path_to_your_image.png', wx.BITMAP_TYPE_PNG) - self.rtc.WriteImage(image) - - vbox.Add(self.rtc, 1, flag=wx.EXPAND) - panel.SetSizer(vbox) - - self.Show() - - -if __name__ == '__main__': - app = wx.App() - MyFrame(None, -1, 'Insert Image in RichTextCtrl') - app.MainLoop()