本文实例为大家分享了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 |