Python学习总结

客户端与服务端聊天窗口

服务端
导入
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_STREAM

class 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=False
        self.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 = False

    def 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_thread
            session_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_socket
        self.user_name = user_name
        self.server = server
        self.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 = 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()))
        # 关闭 socket
        self.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_STREAM

class 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_name
        self.isConnected=False
        self.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=False

    def 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()
相关推荐
soumns丶涛14 分钟前
“conda”不是内部或外部命令,也不是可运行的程序或批处理文件
windows·python·jupyter·conda
一休哥助手16 分钟前
使用 LROPoller 处理 Azure 文档分析时的常见问题及解决方案
后端·python·flask
noravinsc20 分钟前
django models 多条件检索
后端·python·django
初尘屿风21 分钟前
基于Python的Flask微博话题舆情分析可视化系统设计与实现+毕业论文+指导搭建视频
开发语言·python·flask
小志biubiu32 分钟前
Linux版本控制器Git【Ubuntu系统】
linux·运维·服务器·git·学习·ubuntu
烟雨迷42 分钟前
八大排序算法(C语言实现)
c语言·数据结构·学习·算法·排序算法
liruiqiang051 小时前
线性模型 - 支持向量机(参数学习)
人工智能·学习·机器学习·支持向量机
电商数据girl1 小时前
关于酒店旅游信息的数据采集API接口返回||包含参数说明
java·大数据·开发语言·数据库·json·旅游
Ttang231 小时前
JavaWeb基础专项复习4——会话对象Session and Cookie
java·开发语言
编织幻境的妖1 小时前
python的Tkinter小程序上传Excel并下载Text
python·小程序·excel