基于python实现聊天室程序

论坛 期权论坛 脚本     
niminba   2021-5-23 03:54   1351   0

本文实例为大家分享了python实现简单聊天室的具体代码,供大家参考,具体内容如下

刚刚接触python编程,又从接触java开始一直对socket模块感兴趣,所以就做了一个聊天室的小程序。

该程序由客户端与服务器构成,使用UDP服务,服务器端绑定本地IP和端口,客户端由系统随机选择端口。

实现了群发、私发、点对点文件互传功能。

客户端自建了一个类继承了Cmd模块,使用自定义的命令command进行操作,调用相应的do_command方法。

使用json模块进行消息的封装序列化,在接收方进行解析。

客户端代码如下:

import socket
import threading
import json
import os
from cmd import Cmd
 
 
class Client(Cmd):
 """
 客户端
 """
 prompt = '>>>'
 intro = '[Welcome] 简易聊天室客户端(Cli版)\n' + '[Welcome] 输入help来获取帮助\n'
 buffersize = 1024
 
 def __init__(self, host):
  """
  构造
  """
  super().__init__()
  self.__socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  # self.__id = None
  self.__nickname = None
  self.__host = host
  self.thread_recv = None
  self.threadisalive = False
  # 是否在接收文件
  self.recvfile = False
  # 是否在发送文件
  self.sendfile = False
  self.filesize = None
  self.sendfilesize = None
 
  # 接收文件包计数
  self.filecount = None
  # 接收文件名
  self.filename = None
  # 发送文件名
  self.sendfilename = None
 
  # 发送者
  self.filefrom = None
  # 接收者
  self.fileto = None
 
  # 接收文件流
  self.file_recv = None
  # 发送文件流
  self.file_send = None
 
  # 接收文件地址
  self.filefrom_addr = None
  # 发送文件地址
  self.fileto_addr = None
 
 def __receive_message_thread(self):
  """
  接受消息线程
  """
  while self.threadisalive:
   # noinspection PyBroadException
   try:
    buffer, addr = self.__socket.recvfrom(1024)
    '''
    文件流由发送端直接发送,不经过服务器,故当发送端发来的消息时,将收到的数据存入文件
    '''
    if (addr != self.__host) & (addr == self.filefrom_addr) & self.recvfile:
     self.file_recv.write(buffer)
     self.filecount += 1
     if self.filecount * 1024 >= self.filesize:
      self.file_recv.close()
      print(self.filename, 'is received.')
      self.recvfile = False
     continue
 
    js = json.loads(buffer.decode())
 
    # 若接收的数据为消息信息,则显示
    if js['type'] == 'message':
     print(js['message'])
 
    # 若接收的数据为文件发送请求,则存储文件信息,并显示
    elif js['type'] == 'filequest':
     if self.recvfile:
      self.__socket.sendto(json.dumps({
       'type': 'fileres',
       'fileres': 'no',
       'nickname': self.__nickname,
       'who': js['nickname'],
       'errormessage': 'is transfroming files.',
      }).encode(), self.__host)
      continue
     filename = js['filename']
     who = js['nickname']
     filesize = js['filesize']
     self.recvfile = True
     self.filesize = filesize
     self.filename = filename
     self.filecount = 0
     self.filefrom = who
     self.filefrom_addr = (js['send_ip'], js['send_port'])
 
     print('[system]:', who, ' send a file(',
       filename, ') to you. receive? ')
 
    # 接受的数据为请求回复,若同意接收则存储服务器发来的接收方的地址,并开启发送线程
    elif js['type'] == 'fileres':
     if js['fileres'] == 'yes':
      print(js['recv_ip'], js['recv_port'])
      self.fileto_addr = (js['recv_ip'], js['recv_port'])
      thread = threading.Thread(
       target=self.__send_file_thread)
      thread.start()
     else:
      print(js['nickname'], js['errormessage'])
      self.sendfile = False
 
   except Exception as e:
    print(e)
    print('[Client] 无法从服务器获取数据')
 
 def __send_broadcast_message_thread(self, message):
  """
  发送广播消息线程
  :param message: 消息内容
  """
  self.__socket.sendto(json.dumps({
   'type': 'broadcast',
   'nickname': self.__nickname,
   'message': message,
  }).encode(), self.__host)
 
 def __send_file_thread(self):
  """
  发送文件线程
  :param message: 消息内容
  """
  filecount = 0
  print('[system]', 'sending the file...')
  while filecount * 1024 <= self.sendfilesize:
   self.__socket.sendto(
    self.file_send.read(1024), self.fileto_addr)
   filecount += 1
  self.file_send.close()
  self.sendfile = False
  print('[system]', 'the file is sended.')
 
 def __send_whisper_message_thread(self, who, message):
  """
  发送私发消息线程
  :param message: 消息内容
  """
  self.__socket.sendto(json.dumps({
   'type': 'sendto',
   'who': who,
   'nickname': self.__nickname,
   'message': message
  }).encode(), self.__host)
 
 def send_exit(self):
  self.__socket.sendto(json.dumps({
   'type': 'offline',
   'nickname': self.__nickname,
  }).encode(), self.__host)
 
 
 def start(self):
  """
  启动客户端
  """
  self.cmdloop()
 
 def do_login(self, args):
  """
  登录聊天室
  :param args: 参数
  """
  nickname = args.split(' ')[0]
 
  # 将昵称发送给服务器,获取用户id
  self.__socket.sendАЧvG'VSТG'Т&V6VfU6
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP