设计PushServer来将系统间轮询机制转变为实时通讯

很多系统在实现原型时,由于初期对执行效率、处理速度等方面没有苛刻的要求,都会设计成轮询的模型。


而当我们实现完轮询的架构后,可能由于各种需求,需要将系统整体的响应速度缩短。于是我们需要考虑,如何将轮询的机制变为实时通知呢?(具体的应用比如参考HTTP协议,它在设计初期,就是设计成客户端到服务端:请求、响应、断开。HTTP协议非常适合初期窄带宽且网络不稳定的情况下的数据传输,而直到今天,WEB应用仍然沿袭了它最初的设计架构,而大量应用均在此单向连接的基础上开发。

最初如果需要实现服务器通知机制,则需要客户端主动刷新。或者后台客户端去服务端轮询刷新(比如一些使用AJAX的实现)

当我们需要开发实时性非常强的应用的话,这种架构就不合适的。我们可能会使用到comet技术,简而言之就是:请求、挂起、响应。但这样还是有些投机取巧,并且给服务端带来较大的压力……)


OK,言归正传,我们在已有的轮询的系统上,如何影响最小、代码修改量最小的实现PUSH的机制呢?这是本文需要讨论解决的问题。


一般轮询的代码逻辑如下:

while(true){

sleep

logic

}


每次logic中去检测是否有想要的数据。


如果我们能有消息时将sleep迅速结束,而立刻执行logic,则可完成我们的PUSH转变。


那么问题转变为如何将sleep迅速结束?很自然的想到 WaitForSimpleObject,我们每次等一个信号量timeout的时长,可以由另一个线程来Release信号量,这样我们可以立刻执行任务。侦听线程负责接收其他模块的通讯。


问题自然转变为了一个消息派发机制,如果是跨进程的通讯,有人发起信号,有人接收信号。这个就是最典型的聊天室架构了,接口非常简单,每个模块可以join一个频道,可以在各个频道发言,发言后,所有侦听的模块都将立即释放线程锁来执行逻辑。发言的内容可以定义为各个模块自己才懂的私有协议,这样我们只需要修改代码为:


pushclient.joinchannel


while(true){

         pushclient.wait

         logic

}


即可,对整个系统改动极小。


以下给出python的CLIENT端的示例代码,我使用的TCP通讯,自己制定的通讯协议,这里可以仁者见仁了。


PushClientSample.py

#encoding=utf8
'''
Created on 2012-4-16

@author: chenggong
'''

from PushClient import PushClientManager

manager = PushClientManager('192.168.1.113',27000)
manager.join('cutworker')

manager.write('controlcenter','go')
while(True):
    manager.wait(5)
    print 'do work...'
    
manager.close()


PushClient.py
#encoding=utf8
'''
Created on 2012-4-15

@author: chenggong
'''

import socket
import time
import threading

BUFFERSIZE = 1024*20
CMD_END_TAG = "#EndOfCmd#"
taskmutex = threading.Event()
reconnect_interval = 10 #you can set this

class ListenSockThread(threading.Thread):
    def init(self,ip,port):
        self.quit = False
        self.msgbuffer = ""
        self.ip = ip
        self.port = port
        self.channels = []
        
    def close(self):
        self.quit = True
        self.join()
        self.client.close()
    
    def get_msgs(self,msg):
        self.msgbuffer += msg
        list = msg.split(CMD_END_TAG)
        self.msgbuffer = list[-1]
        if(len(list)>1):
            return list[:-1]
        return None
    
    def get_client(self):
        return self.client    
    
    def reconnect(self):
        self.msgbuffer = ""
        try:
            self.client.close()
            self.client = None
        except:
            pass
        
        try:
            self.client = PushClient(self.ip,self.port)
            for c in self.channels:
                self.client.listen(c)
        except:
            return False
        return True
    
    def run(self):
        while(not self.quit):
            try:
                try:
                    msg = self.client.read(BUFFERSIZE)
                except Exception,e:
                    msg = ""
                    if(str(e)!='timed out'):
                        raise e
                list = self.get_msgs(msg)
                if(list==None):
                    continue
                for m in list:
                    self.client.on_get_msg(m)
            except Exception,e:
                if( not self.reconnect()):
                    time.sleep(reconnect_interval)
            
class PushClient:
    def __init__(self,ip,port):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((ip,int(port)))
        self.sock.setblocking(False)
        self.sock.settimeout(1)
    
    def send(self,msg):
        self.sock.send(msg+CMD_END_TAG)    
    
    def write(self,channel,msg):
        self.send("say %s %s"%(channel,msg))
        
    def listen(self,channel):
        self.send("join %s"%channel)
    
    def close(self):
        self.send("quit")
        self.sock.close()
    
    def unlisten(self,channel):
        self.send("exit %s"%channel)
    
    def read(self,buffersize):
        return self.sock.recv(buffersize)
    #override this fun
    def on_get_msg(self,msg):
        if msg == 'go':
            taskmutex.set()
            taskmutex.clear()
            
class PushClientManager():
    def __init__(self,ip,port):
        self.listenThread = ListenSockThread()
        self.listenThread.init(ip,port)
        self.listenThread.start()
    
    def write(self,channel,msg):
        try:
            self.listenThread.get_client().write(channel,msg)
        except:
            self.listenThread.reconnect()
            
    def join(self,channel):
        channel = channel.replace(" ","")
        self.listenThread.channels.append(channel)
        try:
            self.listenThread.get_client().listen(channel)
        except:
            self.listenThread.reconnect()
        
    def exit(self,channel):
        channel = channel.replace(" ","")
        self.listenThread.channels.remove(channel)
        try:
            self.listenThread.get_client().unlisten(channel)
        except:
            self.listenThread.reconnect()
    
    def wait(self,timeout):
        taskmutex.wait(timeout)
        
    def close(self):
        self.listenThread.close()

if __name__ == '__main__':
    manager = PushClientManager('127.0.0.1',27000)
    manager.join('cut worker')
    while(True):
        manager.wait(3)
        print 'do work'
    manager.close()


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值