`

非诚勿扰聊天实现,tornado + redis

阅读更多

 

大家好,下面我和大家分享一下非诚勿扰tornado的实现方式。

非诚勿扰APK地址: http://as.baidu.com/a/item?docid=475931&f=web_alad_1

 

概念介绍:

Comet:基于HTTP长连接的“服务器推”技术

基于Comet的技术主要分为流(streaming)方式和长轮询(long-polling)方式。

首先看Comet这个单词,很多地方都会说到,它是“彗星”的意思,顾名思义,彗星有个长长的尾巴,以此来说明客户端发起的请求是长连的。即用户发起请求后就挂起,等待服务器返回数据,在此期间不会断开连接。流方式和长轮询方式的区别就是:对于流方式,客户端发起连接就不会断开连接,而是由服务器端进行控制。当服务器端有更新时,刷新数据,客户端进行更新;而对于长轮询,当服务器端有更新返回,客户端先断开连接,进行处理,然后重新发起连接。

长轮询(long-polling)方式

流(streaming)方式

根据上面两种方式,我使用了Streaming的方式,原因很简单,在移动互联网的网络环境不如互联网的网络环境,建立tcp链接的开销比较大,所以我们使用streaming方式,在客户端意外断开链接后进行重链接。

具体的实现,其实实现起来

class Chat(object):
    """Chat Redis Server"""

    def __init__(self):
        redis_settings = settings.redis_settings
        config = redis_settings["REDIS_CHAT"]
        self.redis = Redis(config["servers"], config["port"], config["db"])

    def chat_list_key(self, from_user, to_user):
        return "chat_messages:%s:%s" % (from_user.id, to_user.id)

    

    def say(self, from_user, to_user, msg, img,sys='', urla="",urlb=""):
        """chat to some one"""

        #add unread list
        pipeline = self.redis.pipeline()
        try:
            #add msg to unread list
            chat_list_name = self.chat_list_key(from_user, to_user)
            pipeline.rpush(chat_list_name, msg)
            pipeline.execute()
        except:
            pipeline.reset()


    def read(self, from_user, to_user, count=20, set_read=True):
        key = self.chat_list_key(from_user, to_user)

        data = self.redis.lrange(key, 0, count) or []
        if set_read:
            pipeline = self.redis.pipeline()
            try:
                pipeline.delete(key)
                pipeline.execute()
            finally:
                pipeline.reset()
                
        return data

 很简单,简单就是美吗:

 

 

cimport functools
import hashlib
import logging
import struct
import time
import tornado.escape
import tornado.web
from tornado import httpserver
import tornado.websocket
import random

class PollingHandler(tornado.web.RequestHandler):
	def post(self):
		num = random.randint(1, 100)
		self.write("welcome:E" + str(num))
		self.finish()
	

class StreamingHandler(tornado.web.RequestHandler):
	@tornado.web.asynchronous
	def post(self):
		self.get_data(callback=self.on_finish)

	def get_data(self, callback):
		if self.request.connection.stream.closed():
			return
		num = random.randint(1, 100)
		callback(num)

	def on_finish(self, data):
		self.write("Server says: %d" % data)
		self.flush()

		tornado.ioloop.IOLoop.instance().add_timeout(
			time.time() + 3,
			lambda: self.get_data(callback=self.on_finish)
		)


class LongPollingHandler(tornado.web.RequestHandler):
	@tornado.web.asynchronous
	def post(self):
		self.get_data(callback=self.on_finish)

	def get_data(self, callback):
		if self.request.connection.stream.closed():
			return

		num = random.randint(1, 100)
		tornado.ioloop.IOLoop.instance().add_timeout(
			time.time() + 3,
			lambda: callback(num)
		)

	def on_finish(self, data):
		self.write("Server says: %d" % data)
		self.finish()


class WebSocketHandler(tornado.websocket.WebSocketHandler):
	def open(self):
		num = random.randint(1, 100)
		self.write_message("Server Say:"+str(num))

	def on_message(self, message):
		logging.info("getting message %s", message)
		self.write_message("You say:" + message)

	def on_close(self):
		print "[WebSocket closed]......"


if __name__ == "__main__":
	application = tornado.web.Application([
			(r"/websocket", WebSocketHandler),
			(r"/polling", PollingHandler),
			(r"/streaming", StreamingHandler),
			(r"/longpolling", LongPollingHandler),
			(r"/static/(.*)", tornado.web.StaticFileHandler, {"path": "/Users/liuzheng/py.work.dir/comet"}),
	                                         ])

	port = 8888
	print "[start server on port:%s]......." % port
	http_server = httpserver.HTTPServer(application)
	http_server.bind(port)
	http_server.start(2)
	tornado.ioloop.IOLoop.instance().start()

 

 

WebSocket:未来方向

以上不管是Comet的何种方式,其实都只是单向通信,直到WebSocket的出现,才是B/S之间真正的全双工通信。不过目前WebSocket协议仍在开发中,目前Chrome和Safri浏览器默认支持WebSocket,而FF4和Opera出于安全考虑,默认关闭了WebSocket,IE则不支持(包括9),目前WebSocket协议最新的为“76号草案”。有兴趣可以关注http://dev.w3.org/html5/websockets/

附件中有例子,有想完的朋友,拿去玩吧
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics