博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Web聊天室的实现
阅读量:6470 次
发布时间:2019-06-23

本文共 8918 字,大约阅读时间需要 29 分钟。

Tornado普通方式实现聊天室

普通的http方式连接的话,基本思路是前端页面通过JS重复连接后端服务器.

核心文件:app.py

#!/usr/bin/env python# -*- coding:utf-8 -*-import tornado.ioloopimport tornado.webimport timeimport jsonclass IndexHandler(tornado.web.RequestHandler):    def get(self, *args, **kwargs):        self.render('index.html')li = [    {'id':123123, 'content': 'asdfasdfasdf'}]class MsgHandler(tornado.web.RequestHandler):    def get(self, *args, **kwargs):        index = self.get_argument('index')        index = int(index)        if index == 0:            self.write(json.dumps(li))        else:            self.write(json.dumps(li[index:]))settings = {    'template_path': 'views',    'static_path': 'static',}application = tornado.web.Application([    (r"/index.html", IndexHandler),    (r"/msg.html", MsgHandler),], **settings)if __name__ == "__main__":    print('http://127.0.0.1:8006')    application.listen(8006)    tornado.ioloop.IOLoop.instance().start()

index.html聊天页面:

    

tornado异步非阻塞方式

主要处理文件:

import loggingimport tornado.escapeimport tornado.ioloopimport tornado.webimport os.pathimport uuidfrom tornado.concurrent import Futurefrom tornado import genfrom tornado.options import define, options, parse_command_linedefine("port", default=8888, help="run on the given port", type=int)define("debug", default=False, help="run in debug mode")class MessageBuffer(object):    def __init__(self):        self.waiters = set()        self.cache = []        self.cache_size = 200    def wait_for_messages(self, cursor=None):        # Construct a Future to return to our caller.  This allows        # wait_for_messages to be yielded from a coroutine even though        # it is not a coroutine itself.  We will set the result of the        # Future when results are available.        result_future = Future()        if cursor:            new_count = 0            for msg in reversed(self.cache):                if msg["id"] == cursor:                    break                new_count += 1            if new_count:                result_future.set_result(self.cache[-new_count:])                return result_future        self.waiters.add(result_future)        return result_future    def cancel_wait(self, future):        self.waiters.remove(future)        # Set an empty result to unblock any coroutines waiting.        future.set_result([])    def new_messages(self, messages):        logging.info("Sending new message to %r listeners", len(self.waiters))        for future in self.waiters:            future.set_result(messages)        self.waiters = set()        self.cache.extend(messages)        if len(self.cache) > self.cache_size:            self.cache = self.cache[-self.cache_size:]# Making this a non-singleton is left as an exercise for the reader.global_message_buffer = MessageBuffer()class MainHandler(tornado.web.RequestHandler):    def get(self):        self.render("index.html", messages=global_message_buffer.cache)class MessageNewHandler(tornado.web.RequestHandler):    def post(self):        message = {            "id": str(uuid.uuid4()),            "body": self.get_argument("body"),        }        # to_basestring is necessary for Python 3's json encoder,        # which doesn't accept byte strings.        message["html"] = tornado.escape.to_basestring(            self.render_string("message.html", message=message))        if self.get_argument("next", None):            self.redirect(self.get_argument("next"))        else:            self.write(message)        global_message_buffer.new_messages([message])class MessageUpdatesHandler(tornado.web.RequestHandler):    @gen.coroutine    def post(self):        cursor = self.get_argument("cursor", None)        # Save the future returned by wait_for_messages so we can cancel        # it in wait_for_messages        self.future = global_message_buffer.wait_for_messages(cursor=cursor)        messages = yield self.future        if self.request.connection.stream.closed():            return        self.write(dict(messages=messages))    def on_connection_close(self):        global_message_buffer.cancel_wait(self.future)def main():    parse_command_line()    app = tornado.web.Application(        [            (r"/", MainHandler),            (r"/a/message/new", MessageNewHandler),            (r"/a/message/updates", MessageUpdatesHandler),            ],        cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",        template_path=os.path.join(os.path.dirname(__file__), "templates"),        static_path=os.path.join(os.path.dirname(__file__), "static"),        xsrf_cookies=True,        debug=options.debug,        )    app.listen(options.port)    tornado.ioloop.IOLoop.current().start()if __name__ == "__main__":    main()

页面index.html

      
Tornado Chat Demo
{% for message in messages %} {% module Template("message.html", message=message) %} {% end %}
{% module xsrf_form_html() %}

消息页面message.html

{% module linkify(message["body"]) %}

css页面chat.css

body {  background: white;  margin: 10px;}body,input {  font-family: sans-serif;  font-size: 10pt;  color: black;}table {  border-collapse: collapse;  border: 0;}td {  border: 0;  padding: 0;}#body {  position: absolute;  bottom: 10px;  left: 10px;}#input {  margin-top: 0.5em;}#inbox .message {  padding-top: 0.25em;}#nav {  float: right;  z-index: 99;}

js处理页面chat.js

$(document).ready(function() {    if (!window.console) window.console = {};    if (!window.console.log) window.console.log = function() {};    $("#messageform").on("submit", function() {        newMessage($(this));        return false;    });    $("#messageform").on("keypress", function(e) {        if (e.keyCode == 13) {            newMessage($(this));            return false;        }        return true;    });    $("#message").select();    updater.poll();});function newMessage(form) {    var message = form.formToDict();    var disabled = form.find("input[type=submit]");    disabled.disable();    $.postJSON("/a/message/new", message, function(response) {        updater.showMessage(response);        if (message.id) {            form.parent().remove();        } else {            form.find("input[type=text]").val("").select();            disabled.enable();        }    });}function getCookie(name) {    var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");    return r ? r[1] : undefined;}jQuery.postJSON = function(url, args, callback) {    args._xsrf = getCookie("_xsrf");    $.ajax({url: url, data: $.param(args), dataType: "text", type: "POST",            success: function(response) {        if (callback) callback(eval("(" + response + ")"));    }, error: function(response) {        console.log("ERROR:", response);    }});};jQuery.fn.formToDict = function() {    var fields = this.serializeArray();    var json = {};    for (var i = 0; i < fields.length; i++) {        json[fields[i].name] = fields[i].value;    }    if (json.next) delete json.next;    return json;};jQuery.fn.disable = function() {    this.enable(false);    return this;};jQuery.fn.enable = function(opt_enable) {    if (arguments.length && !opt_enable) {        this.attr("disabled", "disabled");    } else {        this.removeAttr("disabled");    }    return this;};var updater = {    errorSleepTime: 500,    cursor: null,    poll: function() {        var args = {"_xsrf": getCookie("_xsrf")};        if (updater.cursor) args.cursor = updater.cursor;        $.ajax({url: "/a/message/updates", type: "POST", dataType: "text",                data: $.param(args), success: updater.onSuccess,                error: updater.onError});    },    onSuccess: function(response) {        try {            updater.newMessages(eval("(" + response + ")"));        } catch (e) {            updater.onError();            return;        }        updater.errorSleepTime = 500;        window.setTimeout(updater.poll, 0);    },    onError: function(response) {        updater.errorSleepTime *= 2;        console.log("Poll error; sleeping for", updater.errorSleepTime, "ms");        window.setTimeout(updater.poll, updater.errorSleepTime);    },    newMessages: function(response) {        if (!response.messages) return;        updater.cursor = response.cursor;        var messages = response.messages;        updater.cursor = messages[messages.length - 1].id;        console.log(messages.length, "new messages, cursor:", updater.cursor);        for (var i = 0; i < messages.length; i++) {            updater.showMessage(messages[i]);        }    },    showMessage: function(message) {        var existing = $("#m" + message.id);        if (existing.length > 0) return;        var node = $(message.html);        node.hide();        $("#inbox").append(node);        node.slideDown();    }};

可在这下载:

转载地址:http://oucko.baihongyu.com/

你可能感兴趣的文章
DATAGUARD维护:从库宕机后如何恢复到管理恢复模式
查看>>
U-BOOT之一:BootLoader 的概念与功能
查看>>
我的路上
查看>>
Velocity处理多余空白和多余空白行问题
查看>>
java值传递
查看>>
DB2与oracle有什么区别
查看>>
创建一个多级文件目录
查看>>
Picasa生成图片幻灯片页面图文教程
查看>>
js获取当前时间的前一天/后一天
查看>>
Python字符串的格式化
查看>>
C#反射---属性
查看>>
服务器常用的状态码及其对应的含义如下
查看>>
zoom和transform:scale的区别
查看>>
幸福框架:可扩展的、动态的、万能的 编号生成器
查看>>
黄聪:PHP 防护XSS,SQL,代码执行,文件包含等多种高危漏洞
查看>>
svn status 显示 ~xx
查看>>
常用HiveQL总结
查看>>
[转]使用Visual Studio Code开发Asp.Net Core WebApi学习笔记(三)-- Logger
查看>>
POJ 3311 Hie with the Pie(状压DP + Floyd)
查看>>
HDU 1402 A * B Problem Plus FFT
查看>>