最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于python實(shí)現(xiàn)聊天室程序

 更新時(shí)間:2018年07月27日 17:25:35   作者:woaidouya123  
這篇文章主要為大家詳細(xì)介紹了基于python實(shí)現(xiàn)聊天室程序,該程序由客戶端與服務(wù)器構(gòu)成,使用UDP服務(wù),實(shí)現(xiàn)了群發(fā)、私發(fā)、點(diǎn)對(duì)點(diǎn)文件互傳功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了python實(shí)現(xiàn)簡(jiǎn)單聊天室的具體代碼,供大家參考,具體內(nèi)容如下

剛剛接觸python編程,又從接觸java開(kāi)始一直對(duì)socket模塊感興趣,所以就做了一個(gè)聊天室的小程序。

該程序由客戶端與服務(wù)器構(gòu)成,使用UDP服務(wù),服務(wù)器端綁定本地IP和端口,客戶端由系統(tǒng)隨機(jī)選擇端口。

實(shí)現(xiàn)了群發(fā)、私發(fā)、點(diǎn)對(duì)點(diǎn)文件互傳功能。

客戶端自建了一個(gè)類繼承了Cmd模塊,使用自定義的命令command進(jìn)行操作,調(diào)用相應(yīng)的do_command方法。

使用json模塊進(jìn)行消息的封裝序列化,在接收方進(jìn)行解析。

客戶端代碼如下:

import socket
import threading
import json
import os
from cmd import Cmd
 
 
class Client(Cmd):
 """
 客戶端
 """
 prompt = '>>>'
 intro = '[Welcome] 簡(jiǎn)易聊天室客戶端(Cli版)\n' + '[Welcome] 輸入help來(lái)獲取幫助\n'
 buffersize = 1024
 
 def __init__(self, host):
  """
  構(gòu)造
  """
  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
  # 是否在發(fā)送文件
  self.sendfile = False
  self.filesize = None
  self.sendfilesize = None
 
  # 接收文件包計(jì)數(shù)
  self.filecount = None
  # 接收文件名
  self.filename = None
  # 發(fā)送文件名
  self.sendfilename = None
 
  # 發(fā)送者
  self.filefrom = None
  # 接收者
  self.fileto = None
 
  # 接收文件流
  self.file_recv = None
  # 發(fā)送文件流
  self.file_send = None
 
  # 接收文件地址
  self.filefrom_addr = None
  # 發(fā)送文件地址
  self.fileto_addr = None
 
 def __receive_message_thread(self):
  """
  接受消息線程
  """
  while self.threadisalive:
   # noinspection PyBroadException
   try:
    buffer, addr = self.__socket.recvfrom(1024)
    '''
    文件流由發(fā)送端直接發(fā)送,不經(jīng)過(guò)服務(wù)器,故當(dāng)發(fā)送端發(fā)來(lái)的消息時(shí),將收到的數(shù)據(jù)存入文件
    '''
    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())
 
    # 若接收的數(shù)據(jù)為消息信息,則顯示
    if js['type'] == 'message':
     print(js['message'])
 
    # 若接收的數(shù)據(jù)為文件發(fā)送請(qǐng)求,則存儲(chǔ)文件信息,并顯示
    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? ')
 
    # 接受的數(shù)據(jù)為請(qǐng)求回復(fù),若同意接收則存儲(chǔ)服務(wù)器發(fā)來(lái)的接收方的地址,并開(kāi)啟發(fā)送線程
    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] 無(wú)法從服務(wù)器獲取數(shù)據(jù)')
 
 def __send_broadcast_message_thread(self, message):
  """
  發(fā)送廣播消息線程
  :param message: 消息內(nèi)容
  """
  self.__socket.sendto(json.dumps({
   'type': 'broadcast',
   'nickname': self.__nickname,
   'message': message,
  }).encode(), self.__host)
 
 def __send_file_thread(self):
  """
  發(fā)送文件線程
  :param message: 消息內(nèi)容
  """
  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):
  """
  發(fā)送私發(fā)消息線程
  :param message: 消息內(nèi)容
  """
  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):
  """
  啟動(dòng)客戶端
  """
  self.cmdloop()
 
 def do_login(self, args):
  """
  登錄聊天室
  :param args: 參數(shù)
  """
  nickname = args.split(' ')[0]
 
  # 將昵稱發(fā)送給服務(wù)器,獲取用戶id
  self.__socket.sendto(json.dumps({
   'type': 'login',
   'nickname': nickname,
  }).encode(), self.__host)
  # 嘗試接受數(shù)據(jù)
 
  buffer = self.__socket.recvfrom(1300)[0].decode()
  obj = json.loads(buffer)
  if obj['login'] == 'success':
   self.__nickname = nickname
   print('[Client] 成功登錄到聊天室')
   self.threadisalive = True
   # 開(kāi)啟子線程用于接受數(shù)據(jù)
   self.thread_recv = threading.Thread(
    target=self.__receive_message_thread)
   self.thread_recv.setDaemon(True)
   self.thread_recv.start()
  else:
   print('[Client] 無(wú)法登錄到聊天室', obj['errormessage'])
 
 def do_send(self, args):
  """
  發(fā)送消息
  :param args: 參數(shù)
  """
  if self.__nickname is None:
   print('請(qǐng)先登錄!login nickname')
   return
  message = args
  # 開(kāi)啟子線程用于發(fā)送數(shù)據(jù)
  thread = threading.Thread(
   target=self.__send_broadcast_message_thread, args=(message, ))
  thread.setDaemon(True)
  thread.start()
 
 def do_sendto(self, args):
  """
  發(fā)送私發(fā)消息
  :param args: 參數(shù)
  """
  if self.__nickname is None:
   print('請(qǐng)先登錄!login nickname')
   return
  who = args.split(' ')[0]
  message = args.split(' ')[1]
  # # 顯示自己發(fā)送的消息
  # print('[' + str(self.__nickname) + '(' + str(self.__id) + ')' + ']', message)
  # 開(kāi)啟子線程用于發(fā)送數(shù)據(jù)
  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('請(qǐng)先登錄!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('請(qǐng)先登錄!login nickname')
   return
  who = args
  catipmessage = json.dumps({'type': 'catip', 'who': who})
  self.__socket.sendto(catipmessage.encode(), self.__host)
 
 def do_help(self, arg):
  """
  幫助
  :param arg: 參數(shù)
  """
  command = arg.split(' ')[0]
  if command == '':
   print('[Help] login nickname - 登錄到聊天室,nickname是你選擇的昵稱')
   print('[Help] send message - 發(fā)送消息,message是你輸入的消息')
   print('[Help] sendto who message - 私發(fā)消息,who是用戶名,message是你輸入的消息')
   print('[Help] catusers - 查看所有用戶')
   print('[Help] catip who - 查看用戶IP,who為用戶名')
   print('[Help] sendfile who filedir - 向某用戶發(fā)送文件,who為用戶名,filedir為文件路徑')
   print('[Help] getfile filename who yes/no - 接收文件,filename 為文件名,who為發(fā)送者,yes/no為是否接收')
  elif command == 'login':
   print('[Help] login nickname - 登錄到聊天室,nickname是你選擇的昵稱')
  elif command == 'send':
   print('[Help] send message - 發(fā)送消息,message是你輸入的消息')
  elif command == 'sendto':
   print('[Help] sendto who message - 發(fā)送私發(fā)消息,message是你輸入的消息')
  else:
   print('[Help] 沒(méi)有查詢到你想要了解的指令')
 
 def do_exit(self, arg): # 以do_*開(kāi)頭為命令
  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]
  # 判斷是否在發(fā)送文件
  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()

服務(wù)器端主要進(jìn)行消息的分類轉(zhuǎn)發(fā)處理,用戶列表、地址列表的維護(hù)。

服務(wù)器端代碼如下:

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())
  # 登錄消息
  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:
    # 向其他用戶發(fā)送通知
    for i in range(len(conn_list)):
     obj.sendto(json.dumps(
      {
       'type': 'message',
       'message': '[system]' + nickname + '已登錄.'
      }).encode(), conn_list[i])
    user_list.append(nickname)
    conn_list.append(client_address)
    print(nickname, client_address, '登錄成功!')
    obj.sendto(json.dumps({'login': 'success',
          'nickname': nickname}).encode(), client_address)
 
  # 群發(fā)消息
  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])
 
  # 私發(fā)消息
  elif js['type'] == 'sendto':
   who = js['who']
   nickname = js['nickname']
   message = js['message']
   # 檢查用戶是否存在
   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)])
 
  # 查看用戶列表
  elif js['type'] == 'catusers':
   users = json.dumps(user_list)
   obj.sendto(json.dumps(
    {
     'type': 'message',
     'message': users,
    }).encode(),
    client_address)
 
  # 查看用戶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)
 
  # 離線消息
  elif js['type'] == 'offline':
   user_list.remove(js['nickname'])
   conn_list.remove(client_address)
   obj.sendto(
    (js['nickname'] + 'offline.').encode(),
    client_address)
   # 向其他用戶發(fā)送通知
   for i in range(len(conn_list)):
    obj.sendto(json.dumps(
     {
      'type': 'message',
      'message': '[system]' + nickname + '下線了.'
     }).encode(), conn_list[i])
 
  # 發(fā)送文件請(qǐng)求
  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)
 
  # 發(fā)送文件請(qǐng)求回復(fù)
  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)

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • mac下給python3安裝requests庫(kù)和scrapy庫(kù)的實(shí)例

    mac下給python3安裝requests庫(kù)和scrapy庫(kù)的實(shí)例

    今天小編就為大家分享一篇mac下給python3安裝requests庫(kù)和scrapy庫(kù)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • python實(shí)現(xiàn)遞歸查找某個(gè)路徑下所有文件中的中文字符

    python實(shí)現(xiàn)遞歸查找某個(gè)路徑下所有文件中的中文字符

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)遞歸查找某個(gè)路徑下所有文件中的中文字符,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • 10招!看骨灰級(jí)Pythoner玩轉(zhuǎn)Python的方法

    10招!看骨灰級(jí)Pythoner玩轉(zhuǎn)Python的方法

    這篇文章主要介紹了10招!看骨灰級(jí)Pythoner如何玩轉(zhuǎn)Python,需要的朋友可以參考下
    2019-04-04
  • Python實(shí)現(xiàn)一個(gè)自助取數(shù)查詢工具

    Python實(shí)現(xiàn)一個(gè)自助取數(shù)查詢工具

    在數(shù)據(jù)生產(chǎn)應(yīng)用部門,取數(shù)分析是一個(gè)很常見(jiàn)的需求,實(shí)際上業(yè)務(wù)人員需求時(shí)刻變化,最高效的方式是讓業(yè)務(wù)部門自己來(lái)取,減少不必要的重復(fù)勞動(dòng),本文介紹如何用Python實(shí)現(xiàn)一個(gè)自助取數(shù)查詢工具
    2021-06-06
  • Python數(shù)據(jù)類型之String字符串實(shí)例詳解

    Python數(shù)據(jù)類型之String字符串實(shí)例詳解

    這篇文章主要介紹了Python數(shù)據(jù)類型之String字符串,結(jié)合實(shí)例形式詳細(xì)講解了Python字符串的概念、定義、連接、格式化、轉(zhuǎn)換、查找、截取、判斷等常見(jiàn)操作技巧,需要的朋友可以參考下
    2019-05-05
  • Python ''takes exactly 1 argument (2 given)'' Python error

    Python ''takes exactly 1 argument (2 given)'' Python error

    這篇文章主要介紹了Python 'takes exactly 1 argument (2 given)' Python error的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • python實(shí)現(xiàn)通過(guò)隊(duì)列完成進(jìn)程間的多任務(wù)功能示例

    python實(shí)現(xiàn)通過(guò)隊(duì)列完成進(jìn)程間的多任務(wù)功能示例

    這篇文章主要介紹了python實(shí)現(xiàn)通過(guò)隊(duì)列完成進(jìn)程間的多任務(wù)功能,結(jié)合實(shí)例形式分析了Python隊(duì)列完成進(jìn)程間的多任務(wù)以及進(jìn)程池pool相關(guān)操作技巧,需要的朋友可以參考下
    2019-10-10
  • Python中from…import *和import區(qū)別小結(jié)

    Python中from…import *和import區(qū)別小結(jié)

    本文介紹了Python中import和from...import兩種導(dǎo)入模塊的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-12-12
  • Python設(shè)計(jì)模式之工廠方法模式實(shí)例詳解

    Python設(shè)計(jì)模式之工廠方法模式實(shí)例詳解

    這篇文章主要介紹了Python設(shè)計(jì)模式之工廠方法模式,結(jié)合實(shí)例形式較為詳細(xì)的分析了工廠方法模式的概念、原理、用法及相關(guān)操作技巧,需要的朋友可以參考下
    2019-01-01
  • 如何讓Python在HTML中運(yùn)行

    如何讓Python在HTML中運(yùn)行

    這個(gè)名為PyScript的框架,其核心目標(biāo)是為開(kāi)發(fā)者提供在標(biāo)準(zhǔn)HTML中嵌入Python代碼的能力,使用?Python調(diào)用JavaScript函數(shù)庫(kù),并以此實(shí)現(xiàn)利用Python創(chuàng)建Web應(yīng)用的功能,本文給大家介紹Python?HTML運(yùn)行的案例解析,感興趣的朋友一起看看吧
    2022-05-05

最新評(píng)論

大名县| 永胜县| 宿松县| 通化县| 香港| 忻城县| 武鸣县| 海伦市| 拉萨市| 巴林左旗| 建水县| 荆州市| 井冈山市| 德惠市| 无极县| 白河县| 东丽区| 眉山市| 惠安县| 乌审旗| 达孜县| 黄大仙区| 怀集县| 黑龙江省| 石柱| 西昌市| 大石桥市| 秦皇岛市| 白水县| 土默特右旗| 河西区| 东阳市| 海南省| 驻马店市| 台湾省| 铜川市| 江都市| 泗水县| 安多县| 建平县| 岚皋县|