# -*- coding: utf-8 -*-
from __future__ import unicode_literals, print_function
from datetime import datetime
import tornado
from tornado.options import define, options
from tornado.websocket import WebSocketHandler
import signal
import sys
# 设置服务器端口
define("port", default=6228, type=int)
class ChatHandler(WebSocketHandler):
users = set() # 用来存放在线用户的容器
def open(self, *args, **kwargs):
id_param = self.get_argument("id", default=None)
print(id_param)
# 建立连接后添加用户到容器中
self.users.add(self)
# 向已在线用户发送消息
for user in self.users:
remote_ip, port = self.request.connection.context.address
now = datetime.now().strftime("%H:%M:%S")
user.write_message("[{}][{}:{}]-进入聊天室".format(now, remote_ip, port))
# 安排定时发送 ping 消息,毫秒,或者把这个方法提出来,弄成全局的定时器,服务于全部在线人群
self.heartbeat_callback = tornado.ioloop.PeriodicCallback(
self.send_heartbeat, 10000
)
self.heartbeat_callback.start()
def on_message(self, message):
# 向在线用户广播消息
now = datetime.now().strftime("%H:%M:%S")
remote_ip, port = self.request.connection.context.address
for user in self.users:
user.write_message("[{}][{}:{}] {}".format(now, remote_ip, port, message))
def on_close(self):
# 用户关闭连接后从容器中移除用户
now = datetime.now().strftime("%H:%M:%S")
remote_ip, port = self.request.connection.context.address
self.users.remove(self)
self.heartbeat_callback.stop()
for user in self.users:
user.write_message("[{}][{}:{}]-离开聊天室".format(now, remote_ip, port))
def check_origin(self, origin):
return True # 允许WebSocket的跨域请求
# 发送心跳的方法
def send_heartbeat(self):
try:
# 发送 ping 消息
self.write_message("ping", binary=False)
except Exception as e:
# 如果发送失败,可能是连接已经关闭
self.users.remove(self)
self.heartbeat_callback.stop()
for user in self.users:
user.write_message("离开聊天室")
def router():
return tornado.web.Application([
(r"/ws", ChatHandler),
],
debug=True
)
def main():
app = router()
# 设置信号处理器,优雅地处理 SIGINT 信号
def signal_handler(sig, frame):
print('Stopping Tornado web server...')
tornado.ioloop.IOLoop.current().stop()
sys.exit(0)
tornado.options.parse_command_line()
signal.signal(signal.SIGINT, signal_handler)
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.current().start()
if __name__ == "__main__":
main()