使用python和tornado实现多人聊天界面
-------------------不要完全盗用哦~----------------------
功能包括:登录、注册、聊天、多人聊天室、增加聊天室。
建议先了解基础知识:
1.python
2.tonado
3.numpy
4.Visual Studio Code编程环境
实验设计
(包括项目结构、方案简要说明等)(1) 项目结构:对于本次项目,项目结构分为chatHander.py后端处理程序、templates文件(包含各种用到的html文件)、static文件(包含用到的图片,js文件和css文件)
方案说明
1.对于实现多人聊天室的功能:·登录页面。登录页面让用户输入用户账户和密码进行登录,后端能获得用户输入的信息,并且对用户的信息进行验证处理,所以后端需要有一个保存用户信息的变量,如果用户信息验证不过,则需要跳转到出错页面或者注册页面。
2.注册页面。用户首次登陆必须要注册账号,后端保存新的用户信息,注册成功后将跳转到 登陆页面登录。注册页面又有密码验证功能,如果用户两次输入的密码不同,将会跳转到出错页面,将出错信息输出再跳转回注册界面。
3.聊天室首页面。用户在登录成功后晶进入个人用户主页面,功能包含聊天室编号、创建新的聊天室、刷新页面、退出登录。
- 聊天室编号:显示当前所有聊天室,用户点击后将直接进入聊天页面。
- 创建新的聊天室:用户可以选择创建新的聊天室,点击后进入聊天室设置(设置聊天室名字)。
- 刷新页面:当前有人创建了新的聊天室,但对于其他用户停留在主页面时,需要刷新才能显示出新的聊天室。
- 退出登录:点击后,用户退出登录,将进入登录界面。可以选择更换账号登录。
- 聊天页面。用户选择聊天室,进入聊天页面,功能上用户可以发送消息,可以选择回到主 页面再选择聊天室。
- 创建新的聊天室。用户选择创建新的聊天室,进入设置页面,设置新的聊天室名字,创建后直接返回用户的主页面,并把所有聊天室显示出来。
- 出错页面。前面提到的错误在出错页面可以将错误信息显示出来,通过自动跳转,回到指定的路由url。
源代码
chatHandler.py
1.后端代码:
# -*-coding:utf-8-*-
import json
import tornado.web
import tornado.websocket
import tornado.httpserver
import tornado.ioloop
import tornado.options
from uuid import uuid4
import time
import numpy as np
np.random.seed(1234)
ls = ['*', '**', '***', '#', '##', '###', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j']
users_info = {'ABC': '12345678', 'hhm': '123456'} # 保存所有用户的账户和密码信息
users_data = {'1': {}, '2': {}} # 保存所有聊天室下、所有用户在线时所记录的各种聊天信息,用于保存历史记录
online = [] # 以用户名来保存当前登录的用户
users_nums = {} # 记录每个聊天室在线的成员,用于显示在线人数。
class LoginHandler(tornado.web.RequestHandler):
'''
登录:
用户选择直接登录或者注册新账户;
用户信息验证过程;
出错信息和跳转;
'''
def get(self, *args, **kwargs):
self.render("login.html", type_="login") # 登陆页面
def post(self, *args, **kwargs):
# 信息验证和出错管理
username = str(self.get_argument("id"))
passwd = str(self.get_argument("passwd"))
if username in users_info:
if username in online:
online.remove(username)
self.render('error.html',
info={'status': False,
'errorcontnet': '友情提示!',
'info': "该用户已经在线!将自动跳转界面",
'second': 2,
'url': '/basic/?u=%s' % (username),
}
)
else:
if passwd == users_info[username]:
online.append(username)
self.render(
'basic.html',
id=username,
session=username,
rooms=users_data,
) # 进入
else:
self.render('error.html',
info={'status': False,
'errorcontnet': '出错了》~《',
'info': "用户名密码错误!将自动跳转注册界面",
'second': 3,
'url': '/login',
}
)
else:
self.render(
"error.html",
info={'status': False,
'errorcontnet': '出错了》~《',
'info': "该用户没有注册,请先注册!将自动跳转注册界面",
'second': 2,
'url': '/register/',
},
)
class RegisterHandler(tornado.web.RequestHandler):
'''
注册:
新用户注册信息注册和验证;
出错信息和跳转;
'''
def get(self, *args, **kwargs):
self.render('register.html') # 注册页面
def post(self, *args, **kwargs):
# 信息验证和出错管理
username = self.get_argument('id')
passwd = self.get_argument('passwd')
passwd1 = self.get_argument('passwd1')
if username not in users_info:
if passwd == passwd1:
users_info[username] = passwd
self.render(
'success.html',
info={
'status': True,
'info': "注册成功!自动跳转登录界面",
'second': 2,
'url': '/login',
}
)
else:
self.render(
'error.html',
info={
'status': False,
'errorcontnet': '出错了》~《',
'info': "密码不一致!自动跳转注册界面",
'second': 2,
'url': '/register/',
}
)
else:
self.render(
'error.html',
info={
'status': False,
'errorcontnet': '出错了》~《',
'info': "用户已经注册!",
'second': 5,
'url': '/login',
}
)
class chatBasicHandler(tornado.web.RequestHandler):
'''
主页:
选择进入聊天室;
创建聊天室;
'''
def get(self, *args, **kwargs):
u = self.get_argument("u")
# 进入用户聊天室主页面
self.render('basic.html',
id=u,
session=u,
rooms=users_data,
)
def post(self, *args, **kwargs):
# 用户聊天室创建
room_name = str(self.get_argument("new_room"))
u = self.get_argument("u")
if room_name in users_data:
room_name = room_name + '**'
users_data[room_name] = {}
self.redirect('/basic')
else:
users_data[room_name] = {}
self.redirect('/basic')
class CreateHandler(tornado.web.RequestHandler):
'''
创建聊天室:
设置聊天室名字
'''
def get(self, *args, **kwargs):
u = self.get_argument('u')
self.render(
'create.html',
id=u,
)
def post(self, *args, **kwargs):
u = self.get_argument('u')
room_name = str(self.get_argument("new_room"))
if room_name in users_data:
v = np.random.choice(ls, 1, False)
room_name = room_name + str(v[0])
users_data[room_name] = {}
self.redirect('/basic/?u=%s' % (u))
else:
users_data[room_name] = {}
self.redirect('/basic/?u=%s' % (u))
class homeHandler(tornado.web.RequestHandler):
'''
聊天室, 获取主页选择聊天室跳转的get信息渲染页面
'''
def get(self, *args, **kwargs):
n = self.get_argument('n') # 聊天室
u = self.get_argument('u') # 用户
self.render('home.html', n=n, u=u, id=u)
class newChatStatus(tornado.websocket.WebSocketHandler):
'''
websocket, 记录客户端连接,删除客户端连接,接收最新消息
'''
users = {} # 在线的用户(以类信息保存)
time = 0 # 记录时间
# 进入聊天室
def open(self):
# 显示时间
self.time = time.time()
self.write_message(json.dumps({'from': 'sys', 'message': '%s' % (time.strftime('%Y-%m-%d %H:%M:%S'))}))
n = str(self.get_argument('n')) # 聊天室
u = str(self.get_argument('u')) # 用户
# 记录在线的用户(全局保存,且以用户名保存)
if u in online:
pass
else:
online.append(u)
# 记录每个房间时在线人数
if n in users_nums:
users_nums[n].append(u)
else:
users_nums[n] = []
users_nums[n].append(u)
# 向新加入用户发送首次消息
self.write_message(json.dumps({'from': 'sys', 'message': '欢迎%s来到 聊天室(%s)' % (u, n)}))
# 显示历史记录
if n in users_data:
if u in users_data[n]:
for m in users_data[n][u]:
self.write_message(json.dumps({'from': m[0], 'message': m[1]}))
# 添加在线用户(类信息)
if n in self.users:
self.users[n].append(self)
else:
self.users[n] = [self]
message = {
'from': 'sys', 'message': '%s加入聊天室%s(当前%d人在线)' % (u, n, len(users_nums[n]))
}
# 向每个聊天室成员发送消息
for user in self.users[n]:
user.write_message(json.dumps(message))
# 离开聊天室
def on_close(self):
n = str(self.get_argument('n')) # 聊天室
u = str(self.get_argument('u')) # 用户
online.remove(u) # 删除离开聊天室的用户
# 人数减1
if n in users_nums:
if u in users_nums[n]:
users_nums[n].remove(u)
# 删除用户(类信息
self.users[n].remove(self)
if self.users[n]:
message = {
'from': 'sys',
'message': '%s离开了聊天室%s(当前%d人在线)' % (u, n, len(users_nums[n]))
}
# 向聊天室里的每个成员发送消息
for user in self.users[n]:
user.write_message(json.dumps(message))
# 用户发送消息
def on_message(self, message):
t1 = time.time()
# 定时显示消息
if t1 - self.time > 120:
self.time = t1
self.write_message(json.dumps({'from': 'sys', 'message': '%s' % (time.strftime('%Y-%m-%d %H:%M:%S'))}))
n = str(self.get_argument('n'))
u = str(self.get_argument('u'))
message = {'from': u, 'message': message}
# 保存用户发送的消息,只要在线的都要保存
if n in users_data:
for user in users_nums[n]:
if user in users_data[n]:
users_data[n][user].append((u, message['message']))
else:
users_data[n][user] = []
users_data[n][user].append((u, message['message']))
else:
users_data[n] = {}
for user in users_nums[n]:
users_data[n][user] = []
users_data[n][user].append((u, message['message']))
# 向每个在线人员发送新消息
for user in self.users[n]:
user.write_message(json.dumps(message))
class Application(tornado.web.Application):
def __init__(self):
handlers = [
(r'/login', LoginHandler),
(r'/register/', RegisterHandler),
(r'/home/', homeHandler),
(r'/basic/', chatBasicHandler),
(r'/newChatStatus/', newChatStatus),
(r'/create/', CreateHandler),
]
settings = {
'template_path': 'template',
'static_path': 'static'
}
tornado.web.Application.__init__(self, handlers, **settings)
if __name__ == '__main__':
tornado.options.parse_command_line()
server = tornado.httpserver.HTTPServer(Application())
server.listen(8000) # 监听端口
tornado.ioloop.IOLoop.instance().start()
剩余代码请参见我的下一个博客。
谢谢你的浏览~
-------------------不要完全盗用哦~----------------------