Python 第14章-项目案例

client代码

# coding:utf-8
import wx
from socket import socket, AF_INET, SOCK_STREAM
import threading


class YsjClient(wx.Frame):
    def __init__(self, client_name):
        # 调用父类的初始化方法
        # id:当前窗口的编号
        # pos:窗体的打开位置
        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(pl, size=(200, 40), label='连接')
        dis_conn_btn = wx.Button(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)

        # 可伸缩的网格布局
        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.RIGHT)
        box.Add(fgz2, 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_server, dis_conn_btn)

        self.Bind(wx.EVT_BUTTON, self.reset, reset_btn)
    def reset(self,event):
        self.chat_text.Clear()
    def dis_conn_server(self,event):
        self.client_socket.send('bye'.encode('utf-8'))
        self.isConnected=False
    def send_to_server(self,event):
        if self.isConnected:
            input_data=self.chat_text.GetValue()
            self.client_socket.send(input_data.encode('utf-8'))
            self.chat_text.SetValue('')
    def connect_to_server(self, event):
        if not self.isConnected:
            server_host_port = ('127.0.0.1', 8888)
            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()


            print(f'客户端{self.client_name}连接服务器成功')

    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 = YsjClient(name)
    client.Show()

    # 循环刷新显示
    app.MainLoop()

server代码

# coding:utf-8
import threading
import time

import wx
from socket import socket, AF_INET, SOCK_STREAM


class YsjServer(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, id=1002, title='Ysj工作室服务器端界面', 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)
        fgz1.Add(record_btn, 1, wx.TOP)
        fgz1.Add(stop_server_btn, 1, wx.TOP)

        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)
        self.

        pl.SetSizer(box)
        '''---------------------以上代码为界面部分------------------------'''
        self.isOn = False
        self.host_port = ('', 8888)  # 空字符代码本机的所有IP

        self.server_socket = socket(AF_INET, SOCK_STREAM)
        self.server_socket.bind(self.host_port)
        self.server_socket.listen(5)
        self.session_thread_dict = {}

        # 鼠标点击“启动服务”按钮时进行的操作
        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.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.server_socket.close()

    def show_info_and_send_client(self, data_source, data, datetime):
        send_data = f'{data_source}:{data}\n时间:{datetime}'
        # 只读文本框
        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

    def run(self) -> None:
        print(f'客户端:{self.user_name}已经和服务器连接成功,服务器启动一个会话线程')
        while self.isOn:
            # 从客户端接收数据
            data = self.client_socket.recv(1024).decode('utf-8')
            if data == 'bye':
                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()))
        self.client_socket.close()


if __name__ == '__main__':
    # 初始化app
    app = wx.App()
    server = YsjServer()
    server.Show()

    # 循环刷新显示
    app.MainLoop()

示例中代码仅能在Windows环境中运行,macOS执行会报错。

wxPython是三方调用的Windows窗体,不支持macOS。

注:本文中的示例出自@Python_子木的视频

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值