鱼C论坛

 找回密码
 立即注册
查看: 1889|回复: 0

[作品展示] Python简易服务器

[复制链接]
发表于 2020-11-23 22:50:17 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
创造两个文件,一个是聊天室服务器,另外一个是聊天室客户端
聊天室服务器代码为:

  1. import wx
  2. from socket import *
  3. import threading
  4. import time

  5. class StoneServer(wx.Frame):
  6.     def __init__(self): #c_name 客户端名字
  7.         #调用父类的初始化函数
  8.         wx.Frame.__init__(self,None,id = 100,title = '石泊远的服务器',pos = wx.DefaultPosition,size = (400,470))
  9.         pa = wx.Panel(self) #在窗口中初始化一个面板
  10.         #在面板里面会放一些按钮,文本框,文本输入框等,把这些对象统一放入一个盒子里面
  11.         box = wx.BoxSizer(wx.VERTICAL) #在盒子里面垂直方向自动排版

  12.         ga = wx.FlexGridSizer(wx.HORIZONTAL)  #可升缩的网格布局,水平方向
  13.         #创建两个按钮
  14.         start_server_button = wx.Button(pa,size = (133,40),label = '启动')
  15.         record_save_button = wx.Button(pa,size = (133,40),label = '聊天记录保存')
  16.         stop_server_button = wx.Button(pa,size = (133,40),label = '停止')
  17.         ga.Add(start_server_button,1,wx.TOP)
  18.         ga.Add(record_save_button,1,wx.TOP)
  19.         ga.Add(stop_server_button,1,wx.TOP)
  20.         box.Add(ga,1,wx.ALIGN_CENTER)

  21.         #创造只读的文本框
  22.         self.text = wx.TextCtrl(pa,size=(400,400),style = wx.TE_MULTILINE | wx.TE_READONLY)
  23.         box.Add(self.text,1,wx.ALIGN_CENTER)
  24.         pa.SetSizer(box)
  25.         '''以上代码窗口结束'''

  26.         '''服务器准备执行的属性'''
  27.         self.isOn = False  #服务器是否启动
  28.         self.host_port = ('',8888)
  29.         self.server_socket = socket(AF_INET,SOCK_STREAM)
  30.         self.server_socket.bind(self.host_port)
  31.         self.server_socket.listen(5)
  32.         self.session_thread_map = {}

  33.         '''给所有的按钮绑定相应的动作'''
  34.         self.Bind(wx.EVT_BUTTON,self.start_server,start_server_button)
  35.         self.Bind(wx.EVT_BUTTON,self.save_record,record_save_button)

  36.     #服务器开始启动函数
  37.     def start_server(self,event):
  38.         print('服务器开始')
  39.         if not self.isOn:
  40.             # 启动服务器的主线程
  41.             self.isOn  = True
  42.             main_thread = threading.Thread(target = self.do_work,)
  43.             main_thread.setDaemon(True)
  44.             main_thread.start()

  45.     #服务器运行之后的函数
  46.     def do_work(self):
  47.         print('开始工作')
  48.         while self.isOn:
  49.             session_socket,client_addr = self.server_socket.accept()
  50.             #服务器首先接受客户端发来的消息
  51.             username = session_socket.recv(1024).decode('UTF-8')
  52.             #创建一个会话线程
  53.             session_thread = SessionThread(session_socket,username,self)
  54.             self.session_thread_map[username] = session_thread
  55.             session_thread.start()
  56.             self.show_info_and_send_client('服务器通知','欢迎%s进入聊天室!'%username,time.strftime('%Y-%m-%d %H:%M:%S',time.localtime()))
  57.         self.server_socket.close()

  58.     def show_info_and_send_client(self,source,data,data_time):
  59.         send_data = '%s : %s\n时间:%s\n' %(source,data,data_time)
  60.         self.text.AppendText('--------------------------------\n%s'%send_data)
  61.         for client in self.session_thread_map.values():
  62.             if client.isOn:
  63.                 client.user_socket.send(send_data.encode('UTF-8'))

  64.     #服务器保存聊天记录
  65.     def save_record(self,event):
  66.         record = self.text.GetValue()
  67.         with open('record.log','w+')as f:
  68.             f.write(record)
  69.         
  70. #服务器端会话线程的类
  71. class SessionThread(threading.Thread):
  72.     def __init__(self,socket,un,server):
  73.         threading.Thread.__init__(self)
  74.         self.user_socket = socket
  75.         self.username = un
  76.         self.server = server
  77.         self.isOn = True
  78.    
  79.     def run(self):
  80.         print('客户端%s,已经和服务器连接成功,服务器启动一个会话线程'%self.username)
  81.         while self.isOn:
  82.             data = self.user_socket.recv(1024).decode('UTF-8')
  83.             if data == 'A^disconnect^B':
  84.                 self.isOn = False
  85.                 #有用户离开
  86.                 self.server.show_info_and_send_client('服务器通知','%s离开聊天室!'%self.username,time.strftime('%Y-%m-%d %H:%M:%S',time.localtime()))
  87.             else:
  88.                 # 其他聊天信息,我们应该显示给所有客户端,包括服务器
  89.                 self.server.show_info_and_send_client(self.username,data,time.strftime('%Y-%m-%d %H:%M:%S',time.localtime()))
  90.         self.user_socket.close()


  91. if __name__ == '__main__':
  92.     app = wx.App()
  93.     StoneServer().Show()
  94.     app.MainLoop() #循环刷新

复制代码


服务器客户端:


  1. import wx
  2. from socket import *
  3. import threading

  4. #客户端继承wx.Frame
  5. class StoneClient(wx.Frame):
  6.     def __init__(self,c_name): #c_name 客户端名字
  7.         #调用父类的初始化函数
  8.         wx.Frame.__init__(self,None,id = 101,title = '%s的客户端'%c_name,pos = wx.DefaultPosition,size = (400,470))
  9.         pa = wx.Panel(self) #在窗口中初始化一个面板
  10.         #在面板里面会放一些按钮,文本框,文本输入框等,把这些对象统一放入一个盒子里面
  11.         box = wx.BoxSizer(wx.VERTICAL) #在盒子里面垂直方向自动排版

  12.         ga = wx.FlexGridSizer(wx.HORIZONTAL)  #可升缩的网格布局,水平方向
  13.         #创建两个按钮
  14.         conn_button = wx.Button(pa,size=(200,40),label="连接")
  15.         dis_conn_button = wx.Button(pa,size=(200,40),label="离开")
  16.         ga.Add(conn_button,1,wx.TOP | wx.LEFT)
  17.         ga.Add(dis_conn_button,1,wx.TOP | wx.RIGHT)
  18.         box.Add(ga,1,wx.ALIGN_CENTER)

  19.         #创建聊天内容的文本框,不可以写消息
  20.         self.text = wx.TextCtrl(pa,size=(400,250),style = wx.TE_MULTILINE | wx.TE_READONLY)
  21.         box.Add(self.text,1,wx.ALIGN_CENTER)

  22.         self.input_text = wx.TextCtrl(pa,size=(400,100),style = wx.TE_MULTILINE)
  23.         box.Add(self.input_text,1,wx.ALIGN_CENTER)
  24.         
  25.         g2 = wx.FlexGridSizer(wx.HORIZONTAL)
  26.         clear_button = wx.Button(pa,size=(200,40),label="重置")
  27.         send_button = wx.Button(pa,size=(200,40),label="发送")
  28.         g2.Add(clear_button,1,wx.TOP | wx.LEFT)
  29.         g2.Add(send_button,1,wx.TOP | wx.RIGHT)
  30.         box.Add(g2,1,wx.ALIGN_CENTER)
  31.         pa.SetSizer(box) #把盒子放入面板中

  32.         '''以上代码完成了客户端界面'''


  33.         '''给所有按钮绑定'''
  34.         self.Bind(wx.EVT_BUTTON,self.connect_to_server,conn_button)
  35.         self.Bind(wx.EVT_BUTTON,self.send_to,send_button)
  36.         self.Bind(wx.EVT_BUTTON,self.go_out,dis_conn_button)
  37.         self.Bind(wx.EVT_BUTTON,self.reset,clear_button)

  38.         '''客户端的属性'''
  39.         self.name = c_name
  40.         self.isConnected = False #客户端是否连上服务器
  41.         self.client_socket = None

  42.     #连接服务器
  43.     def connect_to_server(self,event):
  44.         print('客户端%s,开始连接服务器'%self.name)
  45.         if not self.isConnected:
  46.             server_host_port = ('localhost',8888)
  47.             self.client_socket = socket(AF_INET,SOCK_STREAM)
  48.             self.client_socket.connect(server_host_port)
  49.             #之前规定,客户端只要连接成功,马上把自己的名字发给服务器
  50.             self.client_socket.send(self.name.encode('UTF-8'))
  51.             t = threading.Thread(target = self.receive_data)
  52.             t.setDaemon(True)
  53.             self.isConnected = True
  54.             t.start()
  55.             

  56.     #接受服务器发送过来的聊天数据
  57.     def receive_data(self):
  58.         print('服务器准备接受服务器的数据')
  59.         while self.isConnected:
  60.             data = self.client_socket.recv(1024).decode('UTF-8')
  61.             self.text.AppendText('%s\n'%data)



  62.     #客户端发送信息到客户端
  63.     def send_to(self,event):
  64.         if self.isConnected:
  65.             info = self.input_text.GetValue()
  66.             if info != '':
  67.                 self.client_socket.send(info.encode('UTF-8'))
  68.                 #输入框中的数据如果已经发送了,输入框重新为空
  69.                 self.input_text.SetValue('')

  70.     #客户端离开聊天室
  71.     def go_out(self,event):
  72.         self.client_socket.send('A^disconnect^B'.encode('UTF-8'))
  73.         #客户端关闭
  74.         self.isConnected = False

  75.     #客户端信息重置
  76.     def reset(self,event):
  77.         self.input_text.Clear()
  78.         
  79. if __name__ == '__main__':
  80.     app = wx.App()
  81.     name = input('请输入客户端名字:')
  82.     StoneClient(name).Show()
  83.     app.MainLoop() #循环刷新

复制代码


小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-9 15:04

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表