使用Python简单实现客户端界面

服务端实现

import threading
import timeimport wx
from socket import socket, AF_INET, SOCK_STREAMclass LServer(wx.Frame):def __init__(self):wx.Frame.__init__(self, None, id=1002, title='L服务器端界面', pos=wx.DefaultPosition, size=(400, 450))# 窗口中添加面板pl = wx.Panel(self)# 创建一个盒子box = wx.BoxSizer(wx.VERTICAL)# 创建可伸缩的网格布局fgz1 = wx.FlexGridSizer(wx.HSCROLL)  # 水平方向布局# 创建按钮start_server_btn = wx.Button(pl, size=(133, 40), label='启动服务')record_btn = wx.Button(pl, size=(133, 40), label='保存记录')stop_server_btn = wx.Button(pl, size=(133, 40), label='停止服务')# 将按钮添加到网络布局中fgz1.Add(start_server_btn, 1, wx.TOP | wx.LEFT)fgz1.Add(record_btn, 1, wx.TOP | wx.CENTRE)fgz1.Add(stop_server_btn, 1, wx.TOP | wx.RIGHT)# 将可伸缩的网格布局添加到box中box.Add(fgz1, 1, wx.ALIGN_CENTRE)# 只读文本框,用于显示聊天内容self.show_text = wx.TextCtrl(pl, size=(400, 410), style=wx.TE_MULTILINE | wx.TE_READONLY)box.Add(self.show_text, 1, wx.ALIGN_CENTRE)# 把盒子放到面板中pl.SetSizer(box)'''-----------------------------以上代码为界面的绘制代码-----------------------------------''''''------------------------------设置服务器功能实现的必要属性----------------------------------'''self.isOn = False  # 存储服务器的启动状态,默认False没有启动# 服务器端绑定的IP地址和端口self.host_port = ('', 8888)  # 空的字符串代表的是本机的所有IP# 创建Socket对象self.server_socket = socket(AF_INET, SOCK_STREAM)# 绑定IP地址和端口self.server_socket.bind(self.host_port)# 监听self.server_socket.listen(5)# 创建一个字典,存储与客户端对话的会话线程self.session_thread_dict = {}  # key-value(客户端的名称key:绘画线程value)'''----------------------------------------------------------------'''# 当鼠标点击'启动服务'按钮时,需要执行的操作self.Bind(wx.EVT_BUTTON, self.start_server, start_server_btn)self.Bind(wx.EVT_BUTTON, self.save_record, record_btn)self.Bind(wx.EVT_BUTTON, self.stop_server, stop_server_btn)def stop_server(self,event):#print('服务器已停止服务')self.isOn=Falsedef save_record(self,event):#获取只读文本框的内容record_data=self.show_text.GetValue()with open('record.log','w',encoding='utf-8') as file:file.write(record_data)def start_server(self, event):# 判断服务器是否已经启动,只有服务器没有启动时菜启动if not self.isOn:  # 等监狱self.isOn==False# 启动服务self.isOn = True# 创建主线程对象,函数式创建主线程main_thread = threading.Thread(target=self.do_work)# 设置守护线程,父线程执行结束(窗口界面)子线程也自动关闭main_thread.daemon = True# 启动主线程main_thread.start()def do_work(self):while self.isOn:# 接收客户端的连接请求session_socket, client_addr = self.server_socket.accept()# 客户端发送连接请求后,发送过啊里的第一条数据为客户端名称,客户端的名称去作为字典中的键user_name = session_socket.recv(1024).decode('utf-8')# 创建一个会话线程对象session_thread = SessionThread(session_socket, user_name, self)# 存储到字典中self.session_thread_dict[user_name] = session_thread# 启动会话线程session_thread.start()# 输出服务器的提示信息self.show_info_and_send_client('服务器通知', f'欢迎{user_name}进入聊天室!',time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))# 当self.isOn的值为False时,执行关闭Socket对象self.server_socket.close()def show_info_and_send_client(self, data_source, data, data_time):# 字符串拼接操作send_data = f'{data_source}:{data}\n时间:{data_time}'# 只读文本框self.show_text.AppendText('-' * 40 + '\n' + send_data + '\n')# 每一个客户端都发送一次for client in self.session_thread_dict.values():# 判断当前的会话是否为开启状态if client.isOn:client.client_socket.send(send_data.encode('utf-8'))class SessionThread(threading.Thread):def __init__(self, client_socket, user_name, server):# 调用父类的初始化方法threading.Thread.__init__(self)self.client_socket = client_socketself.user_name = user_nameself.server = serverself.isOn = True  # 会话线程是否启动,当创建SessionThread对象是,会话线程就启动了,所以当前默认为True#def run(self):print(f'客户端:{self.user_name}已经与服务端建立连接.')while self.isOn:# 从客户端接收数据data = self.client_socket.recv(1024).decode('utf-8');# 如果客户端点击断开按钮,先给服务器发送断开连接,消息自定义 C-DISCONNECT-S 自定义结束词if data == 'C-DISCONNECT-S':self.isOn = False# 发送一条服务器通知# 其他聊天信息显示给所有客户端,包含服务器显示self.server.show_info_and_send_client('服务器通知', f'{self.user_name}离开了聊天室',time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))else:# 其他聊天信息显示给所有客户端,包含服务器显示self.server.show_info_and_send_client(self.user_name, data,time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))# 关闭socketself.client_socket.close()if __name__ == '__main__':# 初始化App()app = wx.App()# 创建自己的客户端界面对象client = LServer()client.Show()  # 可以改成LServer().Show()# 循环刷新显示app.MainLoop()

客户端实现

# coding:utf-8
import threadingimport wx
from socket import socket, AF_INET, SOCK_STREAMclass LClinet(wx.Frame):def __init__(self, clent_name):# 调用父类的初始化方法# None:没有父级窗口# id:表示当前窗口的一个编号# title:窗口标题# pos:窗体的打开位置# size:窗体的大小;单位是像素,400宽,450高wx.Frame.__init__(self, None, id=1001, title=clent_name + '的客户端界面', pos=wx.DefaultPosition,size=(400, 600))# 创建面板对象pl = wx.Panel(self)# 在面板中放上盒子box = wx.BoxSizer(wx.VERTICAL)  # 垂直方向布局# 可伸缩的网格布局fgz1 = wx.FlexGridSizer(wx.HSCROLL)  # 水平方向布局# 创建连个按钮connect_btn = wx.Button(pl, size=(200, 40), label='连接')disconnect_btn = wx.Button(pl, size=(200, 40), label='断开')# 把两个按钮放到可伸缩的网格布局fgz1.Add(connect_btn, 1, wx.TOP | wx.LEFT)fgz1.Add(disconnect_btn, 1, wx.TOP | wx.RIGHT)# 可伸缩的网格布局添加到box中box.Add(fgz1, 1, wx.ALIGN_CENTRE)# 只读文本框,用于显示聊天内容self.show_text = wx.TextCtrl(pl, size=(400, 210), style=wx.TE_MULTILINE | wx.TE_READONLY)box.Add(self.show_text, 1, wx.ALIGN_CENTRE)# 创建聊天内容的文本框self.chat_text = wx.TextCtrl(pl, size=(400, 210), style=wx.TE_MULTILINE)box.Add(self.chat_text, 1, wx.ALIGN_CENTRE)# 可伸缩的网格布局fgz2 = wx.FlexGridSizer(wx.HSCROLL)  # 水平方向布局# 创建连个按钮reset_btn = wx.Button(pl, size=(200, 40), label='重置')send_btn = wx.Button(pl, size=(200, 40), label='发送')# 把两个按钮放到可伸缩的网格布局fgz2.Add(reset_btn, 1, wx.TOP | wx.LEFT)fgz2.Add(send_btn, 1, wx.TOP | wx.LEFT)# 可伸缩的网格布局添加到box中box.Add(fgz2, 1, wx.ALIGN_CENTRE)# 将盒子放到面板中pl.SetSizer(box)'''------------------以上代码时客户端界面的绘制---------------------'''self.Bind(wx.EVT_BUTTON, self.connect_to_server, connect_btn)# 实例属性设置self.client_name = clent_nameself.isConnected = False  # 存储客户端连接服务器的状态,默认False未连接self.client_socket = None  # 设置客户端的socket对象为空self.Bind(wx.EVT_BUTTON, self.send_to_server, send_btn)self.Bind(wx.EVT_BUTTON, self.disconnect_to_server, disconnect_btn)self.Bind(wx.EVT_BUTTON, self.reset, reset_btn)def reset(self,event):# 清空文本框self.chat_text.SetValue('')def disconnect_to_server(self,event):#发送断开的信息self.client_socket.send('C-DISCONNECT-S'.encode('utf-8'))# 改变连接状态self.isConnected=Falsedef send_to_server(self, event):# 判断连接状态if self.isConnected:# 从可写文本框中获取输入的内容input_data = self.chat_text.GetValue()if input_data != '':# 向服务器发送数据self.client_socket.send(input_data.encode('utf-8'))# 发送完数据后清空文本框self.chat_text.SetValue('')def connect_to_server(self, event):print(f'客户端{self.client_name}连接服务器成功')# 如果客户端没有连接服务器,则开始连接if not self.isConnected:  # 等价与self.isConnected==False# TCP编程步骤server_host_port = ('127.0.0.1', 8888)# 创建socket对象self.client_socket = socket(AF_INET, SOCK_STREAM)# 发送连接请求self.client_socket.connect(server_host_port)# 只要连接成功,发送一条数据self.client_socket.send(self.client_name.encode('utf-8'))# 启动一个线程,客户端的线程与服务器的会话线程进行会话client_thread = threading.Thread(target=self.recv_data)# 设置线程守护,窗体关闭后,子线程也关闭client_thread.daemon = True# 修改连接状态self.isConnected = True# 启动线程client_thread.start()def recv_data(self):# 判断是否是连接状态while self.isConnected:# 接收服务器的数据data = self.client_socket.recv(1024).decode('utf-8')# 显示到文本框中self.show_text.AppendText('-' * 40 + '\n' + data + '\n')if __name__ == '__main__':# 初始化App()app = wx.App()name = input('请输入客户端名称:')# 创建自己的客户端界面对象client = LClinet(name)client.Show()  # 可以改成LClinet('LL').Show()# 循环刷新显示app.MainLoop()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/59734.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JDK1.5 java代码打包jar HmacSha256

文章目录 demo地址背景实现编写代码编译class文件打包 JAR 文件执行生成的 JAR 文件辅助验证方式 常见问题和解决方法常规生成jar方案maven插件idea工具 demo地址 https://github.com/xiangge-zx/HmacSha256 背景 最近接到一个需求,做一个可以用来HmacSha256加密的小工具&am…

ubuntu 22.04 server 安装 xtrabackup 2.4 qpress LTS

ubuntu 22.04 server 安装 xtrabackup 2.4 qpress LTS 参考 https://docs.percona.com/percona-xtrabackup/innovation-release/apt-repo.html https://www.ubuntuupdates.org/ppa/percona_server_with_xtradb?distjammy centos7 xtrabackup mysql(8&#xff0…

MySQL 8.0中的‘caching_sha2_password‘身份验证插件问题

使用Navicat Premium 12连接MySQL数据库时会出现Authentication plugin ‘caching_sha2_password’ cannot be loaded的错误。 出现这个原因是mysql8 之前的版本中加密规则是mysql_native_password,而在mysql8之后,加密规则是caching_sha2_password, 解决问题方法有两种,一种是…

Go八股(Ⅳ)***slice,string,defer***

***slice,string,defer*** 1.slice和arry的区别 arry: Go语言中arry即为数据的一种集合,需要在声明时指定容量和初值,且一旦声明就长度固定,访问时按照索引访问。通过内置函数len可以获取数组中的元素个…

雪花算法(Snowflake Algorithm)C# 实现版本

这里采用10位的工作ID,当时间回拔时,采用工作ID增加1来避免生成与旧的ID重复。 雪花算法的结构 雪花算法生成的ID是一个64位的Long型数字,结构如下: 高41位:时间戳(timestamp)中间10位:工作节点ID(workerId),用来避免时间回拔。低12位:序列号(sequence)时间戳(…

服务器虚拟化:构建高效、灵活的数据中心

服务器虚拟化:构建高效、灵活的数据中心 在当今数字化时代,服务器虚拟化已经成为构建高效、灵活数据中心的关键技术。通过服务器虚拟化,企业可以将物理服务器划分为多个虚拟服务器,从而提高资源利用率、降低成本、增强灵活性和提…

2024-11-07 问AI: [AI面试题] 解释推荐系统的概念

文心一言 推荐系统是一种信息过滤系统,旨在预测用户对物品的“评分”或“偏好”,并为用户提供个性化的推荐。以下是关于推荐系统的详细解释: 一、定义与功能 推荐系统通过分析和利用用户的历史行为、偏好和其他信息,来预测用户…

Win系统通过命令行查看笔记本电池损耗/寿命/健康

在 Windows 10/11 系统中,可以通过指令查看笔记本电池的寿命情况,方法如下: 0,打开cmd/终端 键盘快捷键:Win R,然后输入cmd,点击【确定】 1,执行命令 在命令行中输入下面指令并按…

103 - Lecture 1

Introduction to Database 一、Introduction to Database Systems 1. 数据的定义 What is Data? EX: data could be a docx file storing your project status report; data could be a spreadsheet containing information • 数据只有在设计的场景中才有意义。&#xff…

前端加密方式详解与选择指南

在当今数字化时代,前端数据安全的重要性日益凸显。本文将深入探讨前端加密的多种方式,为你提供选择适合项目加密方式的实用策略,并分享一些实际案例及相应代码。 一、前端加密方式汇总 (一)HTTPS 加密 HTTPS 是在 H…

【大数据学习 | kafka高级部分】kafka中的选举机制

controller的选举 首先第一个选举就是借助于zookeeper的controller的选举 第一个就是controller的选举,这个选举是借助于zookeeper的独享锁实现的,先启动的broker会在zookeeper的/contoller节点上面增加一个broker信息,谁创建成功了谁就是主…

关于几种卷积

1*1卷积 分组卷积&深度可分离卷积 空洞卷积、膨胀卷积 转置卷积 https://zhuanlan.zhihu.com/p/80041030 https://yinguobing.com/separable-convolution/#fn2 11的卷积可以理解为对通道进行加权,对于一个通道来说,每个像素点加权是一样的&am…

OCR、语音识别与信息抽取:免费开源的AI平台在医疗领域的创新应用

一、系统概述 在医疗行业中,大量数据来自手写病历、医学影像报告、患者对话记录等非结构化数据源。这些数据常常存在信息碎片化和管理困难的问题,给医务人员的工作带来了不便。思通数科AI多模态能力平台正是为了解决这一行业痛点而生,产品集…

Linux驱动开发——零散知识分享

本篇文章记录我学习Linux驱动时的一些零散知识,旨在记录成长,分享心得,希望我的分享能给你带来不一样的收获! 1、C 语言字符串转换为整数二点函数atoi 在 C 语言中,atoi 函数用于将字符串转换为整数。其原型定义在头文…

Git进阶(十八):git rebase详解

文章目录 一、前言二、rebase 图解三、应用示例四、重建提交历史五、rebase VS merge六、拓展阅读 一、前言 rebase 使用方法 git rebase [基节点] git rebase [基节点] [待变基节点]rebase后面的参数可以是两个,也可以是一个,当rebase为一个参数的时…

【React】条件渲染——逻辑与运算符

条件渲染——逻辑与&&运算符 你会遇到的另一个常见的快捷表达式是 JavaScript 逻辑与(&&)运算符。在 React 组件里,通常用在当条件成立时,你想渲染一些 JSX,或者不做任何渲染。 function Item({ nam…

《深度学习》——深度学习基础知识(全连接神经网络)

文章目录 1.神经网络简介2.什么是神经网络3.神经元是如何工作的3.1激活函数3.2参数的初始化3.2.1随机初始化3.2.2标准初始化3.2.3Xavier初始化(tf.keras中默认使用的)3.2.4He初始化 4.神经网络的搭建4.1通过Sequential构建神经网络4.2通过Functional API…

SpringBoot整合Freemarker(二)

if分支 语法&#xff1a; <#if condition>... <#elseif condition2>... <#elseif condition3>... <#else>... </#if> 例子&#xff1a; <#if x 1>x is 1 </#if> --------------------------------- <#if x 1>x is 1 <…

Bsin-kb-agent:企业级AI知识库

企业级AI知识库 Bsin-kb-agent 是基于BsinPaaS开源框架和大语言模型构建的企业知识库应用&#xff0c;借鉴langchain的框架思想&#xff0c;引入langchian4j组件&#xff0c;微前端微服务的架构设计&#xff0c;可快速助您构建和体验端到端的AI知识库应用。 应用场景 企业微…

spark的RDD分区的设定规则

目录 一、第一种&#xff1a;parallelize 获取rdd时 二、第二种&#xff1a;通过外部读取数据-textFile 三、上面提到了默认分区数&#xff0c;那么默认分区是怎么计算呢&#xff1f; 一、第一种&#xff1a;parallelize 获取rdd时 没有指定&#xff1a;spark.default.paral…