Implement chat room program based on python

  • 2020-11-25 07:20:03
  • OfStack

Example of this article for you to share python implementation of simple chat room specific code, for your reference, the specific content is as follows

Just contact python programming, and from contact java 1 directly interested in socket module, so I made a chat room of the small program.

The program consists of the client and the server, using UDP service. The server side binds the local IP and port, and the client side chooses the port randomly by the system.

Realized the mass, private, point - to - point file transfer function.

The client built a class to inherit the Cmd module, used the custom command command to operate, and called the corresponding do_command method.

json module is used to encapsulate and serialize messages and parse them at the receiver.

The client code is as follows:


import socket
import threading
import json
import os
from cmd import Cmd
 
 
class Client(Cmd):
 """
  The client 
 """
 prompt = '>>>'
 intro = '[Welcome]  Simple chat room client (Cli version )\n' + '[Welcome]  The input help To get help \n'
 buffersize = 1024
 
 def __init__(self, host):
  """
   structure 
  """
  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
  #  Whether to receive a file 
  self.recvfile = False
  #  Whether you are sending a file 
  self.sendfile = False
  self.filesize = None
  self.sendfilesize = None
 
  #  Receive file package count 
  self.filecount = None
  #  Receive file name 
  self.filename = None
  #  Send file name 
  self.sendfilename = None
 
  #  The sender 
  self.filefrom = None
  #  The receiver 
  self.fileto = None
 
  #  Receive file stream 
  self.file_recv = None
  #  Send file stream 
  self.file_send = None
 
  #  Receiving file address 
  self.filefrom_addr = None
  #  Send file address 
  self.fileto_addr = None
 
 def __receive_message_thread(self):
  """
   Message receiving thread 
  """
  while self.threadisalive:
   # noinspection PyBroadException
   try:
    buffer, addr = self.__socket.recvfrom(1024)
    '''
     The file flow is sent directly by the sending end without passing through the server, so when the message is sent by the sending end, the received data is stored in the file 
    '''
    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())
 
    #  Displays if the received data is message information 
    if js['type'] == 'message':
     print(js['message'])
 
    #  If the received data is a file send request, the file information is stored and displayed 
    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? ')
 
    #  The data received is the request reply, and if agreed to receive, the address of the recipient sent from the server is stored and the sending thread is opened 
    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]  Unable to retrieve data from server ')
 
 def __send_broadcast_message_thread(self, message):
  """
   Send a broadcast message thread 
  :param message:  The message content 
  """
  self.__socket.sendto(json.dumps({
   'type': 'broadcast',
   'nickname': self.__nickname,
   'message': message,
  }).encode(), self.__host)
 
 def __send_file_thread(self):
  """
   Sending file thread 
  :param message:  The message content 
  """
  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):
  """
   The sending private message thread 
  :param message:  The message content 
  """
  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):
  """
   Start the client 
  """
  self.cmdloop()
 
 def do_login(self, args):
  """
   Log on to chat room 
  :param args:  parameter 
  """
  nickname = args.split(' ')[0]
 
  #  Sends the nickname to the server to get the user id
  self.__socket.sendto(json.dumps({
   'type': 'login',
   'nickname': nickname,
  }).encode(), self.__host)
  #  Attempt to receive data 
 
  buffer = self.__socket.recvfrom(1300)[0].decode()
  obj = json.loads(buffer)
  if obj['login'] == 'success':
   self.__nickname = nickname
   print('[Client]  Login to chat room successfully ')
   self.threadisalive = True
   #  Open child threads to receive data 
   self.thread_recv = threading.Thread(
    target=self.__receive_message_thread)
   self.thread_recv.setDaemon(True)
   self.thread_recv.start()
  else:
   print('[Client]  Unable to log into the chat room ', obj['errormessage'])
 
 def do_send(self, args):
  """
   Send a message 
  :param args:  parameter 
  """
  if self.__nickname is None:
   print(' Please log in first! login nickname')
   return
  message = args
  #  The child thread is opened for sending data 
  thread = threading.Thread(
   target=self.__send_broadcast_message_thread, args=(message, ))
  thread.setDaemon(True)
  thread.start()
 
 def do_sendto(self, args):
  """
   Send private messages 
  :param args:  parameter 
  """
  if self.__nickname is None:
   print(' Please log in first! login nickname')
   return
  who = args.split(' ')[0]
  message = args.split(' ')[1]
  # #  Displays the messages you sent 
  # print('[' + str(self.__nickname) + '(' + str(self.__id) + ')' + ']', message)
  #  The child thread is opened for sending data 
  thread = threading.Thread(
   target=self.__send_whisper_message_thread, args=(who, message))
  thread.setDaemon(True)
  thread.start()
 
 def do_catusers(self, arg):
  if self.__nickname is None:
   print(' Please log in first! login nickname')
   return
  catmessage = json.dumps({'type': 'catusers'})
  self.__socket.sendto(catmessage.encode(), self.__host)
 
 def do_catip(self, args):
  if self.__nickname is None:
   print(' Please log in first! login nickname')
   return
  who = args
  catipmessage = json.dumps({'type': 'catip', 'who': who})
  self.__socket.sendto(catipmessage.encode(), self.__host)
 
 def do_help(self, arg):
  """
   help 
  :param arg:  parameter 
  """
  command = arg.split(' ')[0]
  if command == '':
   print('[Help] login nickname -  Log in to the chat room, nickname Is the nickname you choose ')
   print('[Help] send message -  Send a message, message It's the message that you entered ')
   print('[Help] sendto who message -  Private messaging, who It's the user name, message It's the message that you entered ')
   print('[Help] catusers -  View all users ')
   print('[Help] catip who -  To view the user IP . who To the user name ')
   print('[Help] sendfile who filedir -  Send a file to a user, who Is the user name, filedir Is the file path ')
   print('[Help] getfile filename who yes/no -  To receive files, filename  For the file name ,who For the sender, yes/no To receive or not to receive ')
  elif command == 'login':
   print('[Help] login nickname -  Log in to the chat room, nickname Is the nickname you choose ')
  elif command == 'send':
   print('[Help] send message -  Send a message, message It's the message that you entered ')
  elif command == 'sendto':
   print('[Help] sendto who message -  Sending private messages, message It's the message that you entered ')
  else:
   print('[Help]  No instructions were queried for what you want to know ')
 
 def do_exit(self, arg): #  In order to do_* Begins with a command 
  print("Exit")
  self.send_exit()
  try:
   self.threadisalive = False
   self.thread_recv.join()
  except Exception as e:
   print(e)
  # self.__socket.close()
 
 def do_sendfile(self, args):
  who = args.split(' ')[0]
  filepath = args.split(' ')[1]
  filename = filepath.split('\\')[-1]
  #  Determine if a file is being sent 
  if self.sendfile:
   print('you are sending files, please try later.')
   return
  if not os.path.exists(filepath):
   print('the file is not exist.')
   return
  filesize = os.path.getsize(filepath)
  # print(who, filename, filesize)
 
  self.sendfile = True
  self.fileto = who
  self.sendfilename = filename
  self.sendfilesize = filesize
  self.file_send = open(filepath, 'rb')
 
  self.__socket.sendto(json.dumps({
   'type': 'filequest',
   'nickname': self.__nickname,
   'filename': self.sendfilename,
   'filesize': self.sendfilesize,
   'who': self.fileto,
   'send_ip': '',
   'send_port': '',
  }).encode(), self.__host)
 
  print('request send...')
 
  # fileres = self.__socket.recvfrom(1024)[0].decode()
  # js = json.loads(fileres)
 
 def do_getfile(self, args):
  filename = args.split(' ')[0]
  who = args.split(' ')[1]
  ch = args.split(' ')[2]
  # print(self.filename is not None, filename, self.filename, who, self.filefrom)
  if (self.filename is not None) & (filename == self.filename) & (who == self.filefrom):
   if ch == 'yes':
    self.file_recv = open(self.filename, 'wb')
    self.__socket.sendto(json.dumps({
     'type': 'fileres',
     'fileres': 'yes',
     'nickname': self.__nickname,
     'who': who,
     'recv_ip': '',
     'recv_port': '',
    }).encode(), self.__host)
    print('you agree to reveive the file(', filename, ') from', who)
 
   else:
    self.__socket.sendto(json.dumps({
     'type': 'fileres',
     'fileres': 'no',
     'nickname': self.__nickname,
     'errormessage': 'deny the file.',
     'who': who,
     'recv_ip': '',
     'recv_port': '',
    }).encode(), self.__host)
    print('you deny to reveive the file(', filename, ') from', who)
    self.recvfile = False
  else:
   print('the name or sender of the file is wrong.')
 
 
c = Client(('127.0.0.1', 12346))
c.start()

The server side mainly carries on the classified forwarding processing of the message and the maintenance of the user list and address list.

The server-side code is as follows:


import socket
import json
 
obj = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
obj.bind(('127.0.0.1', 12346))
 
conn_list = []
user_list = []
 
while True:
 try:
  receive_data, client_address = obj.recvfrom(1024)
  js = json.loads(receive_data.decode())
  #  The login information 
  if js['type'] == 'login':
 
   nickname = str(js['nickname'])
   if nickname in user_list:
    obj.sendto(json.dumps({'login': 'fail',
          'errormessage': 'the nickname is exists'}).encode(),
       client_address)
   else:
    #  Send notifications to other users 
    for i in range(len(conn_list)):
     obj.sendto(json.dumps(
      {
       'type': 'message',
       'message': '[system]' + nickname + ' Is logged in .'
      }).encode(), conn_list[i])
    user_list.append(nickname)
    conn_list.append(client_address)
    print(nickname, client_address, ' Login successful! ')
    obj.sendto(json.dumps({'login': 'success',
          'nickname': nickname}).encode(), client_address)
 
  #  Group-sent message 
  elif js['type'] == 'broadcast':
   message = js['message']
   nickname = js['nickname']
   for i in range(len(conn_list)):
    obj.sendto(json.dumps(
     {
      'type': 'message',
      'message': nickname + ':' + message
     }).encode(), conn_list[i])
 
  #  Private message 
  elif js['type'] == 'sendto':
   who = js['who']
   nickname = js['nickname']
   message = js['message']
   #  Check if the user exists 
   if who not in user_list:
    obj.sendto(json.dumps(
     {
      'type': 'message',
      'message': who + ' not exist or not online.please try later.'
     }).encode(),
     client_address)
   else:
    obj.sendto(json.dumps(
     {
      'type': 'message',
      'message': nickname + ' whisper to you: ' + message
     }).encode(),
     conn_list[user_list.index(who)])
 
  #  View user list 
  elif js['type'] == 'catusers':
   users = json.dumps(user_list)
   obj.sendto(json.dumps(
    {
     'type': 'message',
     'message': users,
    }).encode(),
    client_address)
 
  #  To view the user IP
  elif js['type'] == 'catip':
   who = js['who']
   if who not in user_list:
    obj.sendto(json.dumps(
     {
      'type': 'message',
      'message': who + ' not exist or not online.please try later.'
     }).encode(),
     client_address)
   else:
    addr = json.dumps(conn_list[user_list.index(who)])
    obj.sendto(json.dumps(
     {
      'type': 'message',
      'message': addr,
     }).encode(),
     client_address)
 
  #  Offline message 
  elif js['type'] == 'offline':
   user_list.remove(js['nickname'])
   conn_list.remove(client_address)
   obj.sendto(
    (js['nickname'] + 'offline.').encode(),
    client_address)
   #  Send notifications to other users 
   for i in range(len(conn_list)):
    obj.sendto(json.dumps(
     {
      'type': 'message',
      'message': '[system]' + nickname + ' Get offline .'
     }).encode(), conn_list[i])
 
  #  Send file request 
  elif js['type'] == 'filequest':
   who = js['who']
   if who not in user_list:
    obj.sendto(json.dumps(
     {
      'type': 'message',
      'message': who + ' not exist or not online.please try later.'
     }).encode(),
     client_address)
   else:
    js['send_ip'] = client_address[0]
    js['send_port'] = client_address[1]
    obj.sendto(json.dumps(js).encode(),
       conn_list[user_list.index(who)])
    print(js['nickname'], 'request to send file to', who)
 
  #  Send file for reply 
  elif js['type'] == 'fileres':
   who = js['who']
   if js['fileres'] == 'yes':
    js['recv_ip'] = client_address[0]
    js['recv_port'] = client_address[1]
    print(js['nickname'], 'agree to receive file from', js['who'])
   else:
    print(js['nickname'], 'deny to receive file from', js['who'])
   obj.sendto(json.dumps(js).encode(),
      conn_list[user_list.index(who)])
 
 except Exception as e:
  print(e)

Related articles: