Python学习总结

ops/2025/2/24 22:47:07/

客户端与服务端聊天窗口

服务端
导入
wxPython 用于创建图形界面。
socket 用于网络通信,AF_INET 是 IPv4 地址族,SOCK_STREAM 表示流式套接字(TCP)。

利用wxPython 创建图形界面,并通过 socket 与服务器通信。

主要功能:

  • 连接服务器。
  • 发送和接收消息。
  • 断开连接。
  • 界面上有文本框和按钮来操作。
  • wxPython 处理 UI 部分,socket 处理网络通信。
python">import threading
from threading import main_thread, Thread
#coding UTF-8
import self
import wx
import time
from socket import socket,AF_INET,SOCK_STREAMclass YsjServer(wx.Frame):
//通过继承 wx.Frame,我们可以创建一个带有窗口的应用程序。def __init__(self):wx.Frame.__init__(self,None,id=1002,title='某工作室界面')# 创建面板对象pl = wx.Panel(self)# 面板中放盒子box = wx.BoxSizer(wx.VERTICAL)# 可伸缩的网格布局fgz1 = wx.FlexGridSizer(wx.HSCROLL)start_server_btn = wx.Button(parent=pl, size=(133,40), label='启动')record_btn = wx.Button(parent=pl, size=(133, 40), label='保存聊天记录')stop_server_btn = wx.Button(parent=pl, size=(133, 40), label='离开')fgz1.Add(start_server_btn, 1, wx.TOP)fgz1.Add(record_btn, 1, wx.TOP )fgz1.Add(stop_server_btn, 1, wx.TOP)# (可伸缩的网络布局)添加到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=Falseself.host_port=('',8888)# 创建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=True#创建主线程对象main_thread=threading.Thread(target=self.do_work())#设置守护线程,父线程执行结束,子线程也自动关闭main_thread.demon=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_threadsession_thread.start()self.show_info_and_send_client('服务器通知', f'欢迎{user_name}进入聊天室!',time.strftime('%Y-%m-%d %H:%M:%S',time.localtime()))self.server_socket.close()def show_info_and_send_client(self, data_source, data, date_time):# 字符串操作send_data = f'{data_source}:{data}\n时间:{date_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对象时会话线程即启动def run(self) -> None:print(f'客户端:{self.user_name}已经和服务器连接成功,服务器启动一个会话线程')while self.isOn:# 从客户端接收数据 存储到data中data = self.client_socket.recv(1024).decode('utf-8')# 如果客户端点击断开按钮,先给服务器发送一句话, 消息自定义  Y-disconnect-SJ 自定义的结束词儿if data == 'Y-disconnect-SJ':self.isOn = Falseself.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=wx.App()server =YsjServer()server.Show()app.MainLoop()

客户端

python">import wx
#coding UTF-8
from socket import  socket,AF_INET,SOCK_STREAMclass YsJClient(wx.Frame):def __init__(self, client_name):#调用父类的初始化方法#None:表示没有父级窗口#id 表示窗口编号#pos  窗体打开的位置#size 窗体的大小,单位像素wx.Frame.__init__(self,None, id=1001, title=client_name + '的客户端界面',pos=wx.DefaultPosition, size=(400, 450))#创建面板对象pl = wx.Panel(self)#面板中放盒子box = wx.BoxSizer(wx.VERTICAL)# 可伸缩的网格布局fgz1 = wx.FlexGridSizer(wx.HSCROLL)# 水平方向布局# 创建两个按钮conn_btn = wx.Button(parent=pl, size=(200, 40), label='连接')dis_conn_btn = wx.Button(parent=pl, size=(200, 40), label='断开')# 把两个按钮放到可伸缩的网格布局fgz1.Add(conn_btn, 1, wx.TOP | wx.LEFT)fgz1.Add(dis_conn_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, 120), style=wx.TE_MULTILINE)box.Add(self.chat_text, 1, wx.ALIGN_CENTRE)#可绳索网格布局fgz1 = wx.FlexGridSizer(wx.HSCROLL)#两个按钮reset_btn = wx.Button(parent=pl, size=(200, 40), label='重置')send_btn = wx.Button(parent=pl, size=(200, 40), label='发送')fgz1.Add(reset_btn, 1, wx.TOP | wx.LEFT)fgz1.Add(send_btn, 1, wx.TOP | wx.RIGHT)# (可伸缩的网络布局)添加到box中box.Add(fgz1, 1, wx.ALIGN_CENTRE)pl.SetSizer(box)'--------客户端界面绘制--------'self.Bind(wx.EVT_BUTTON, self.connect_to_server, conn_btn)self.client_name=client_nameself.isConnected=Falseself.client_socket=None#发送绑定self.Bind(wx.EVT_BUTTON, self.send_to_server, send_btn)#断开绑定self.Bind(wx.EVT_BUTTON, self.dis_conn_to_server, dis_conn_btn)# 重置绑定self.Bind(wx.EVT_BUTTON, self.reset, reset_btn)def reset(self,event):self.chat_text.Clear()def dis_conn_to_server(self,event):self.client_socket.send('Y-disconnect-SJ'.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:server_host_port=('127.0.0.1',8888)#创建socket对象self.client_socket=socket(AF_INET,SOCK_STREAM)#发送请求self.client_socket.connect(server_host_port)import threading# 只要连接成功,发送一条数据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=wx.App()name=input('请输入客户端名称')client =YsJClient(name)client.Show()app.MainLoop()

http://www.ppmy.cn/ops/161053.html

相关文章

Git 工作流程

1、Git 工作流程 http://www.ruanyifeng.com/blog/2015/12/git-workflow.html git push -f origin HEAD^:master 删除服务器上最近的一次提交git push -f origin HEAD^:master 2、Git分支管理 动画形式演示分支效果: http://onlywei.github.io/explain-git-with-…

蓝桥杯学习笔记03-滑动窗口不定长(最长/最大)

题目来源 分享丨【题单】滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环) - 力扣(LeetCode) 不定长滑动窗口 2024. 考试的最大困扰度 - 力扣(LeetCode) 解决:分别处理‘T’和’…

【从0做项目】Java文档搜索引擎(9)烧脑终章!

阿华代码,不是逆风,就是我疯 你们的点赞收藏是我前进最大的动力!! 希望本文内容能够帮助到你!! 目录 文章导读 零:项目结果展示 一:导入 二:问题引入 1:情…

【DeepSeek】本地部署,保姆级教程

deepseek网站链接传送门:DeepSeek 在这里主要介绍DeepSeek的两种部署方法,一种是调用API,一种是本地部署。 一、API调用 1.进入网址Cherry Studio - 全能的AI助手选择立即下载 2.安装时位置建议放在其他盘,不要放c盘 3.进入软件后…

技术分享:MyBatis SQL 日志解析脚本

技术分享:MyBatis SQL 日志解析脚本 1. 脚本功能概述2. 实现细节2.1 HTML 结构2.2 JavaScript 逻辑 3. 脚本代码4. 使用方法4.1 示例 5. 总结 在日常开发中,使用 MyBatis 作为持久层框架时,我们经常需要查看 SQL 日志以调试和优化查询。然而&…

Docker入门及基本概念

让我们从最基础的概念开始逐步理解。假设你已经准备好了docker 环境。 第一步,让我们先通过实际操作来看看当前系统中的镜像(images)和容器(containers)状态: docker images # 查看所有镜像 docker ps -a # 查看所有容器(包括未运行…

postman调用ollama的api

按照如下设置,不需要设置key 保持长会话的方法 # 首次请求 curl http://localhost:11434/api/generate -d {"model": "deepseek-r1:32b","prompt": "请永久记住:110,1-12,之后所有数学计算必…

QT 基础知识点

1.基础窗口类QMainWindow qDialog Qwidget 随项目一起创建的窗口基类有三个可选QMainWindow qDialog Qwidget 1.1 Qwidget 是所有窗口的基类,只要是他的子类,或子类的子类,都具有他的属性。 右键项目 Add New -> Qt qt设计师界面类&am…