設計PushServer來將系統間輪詢機制轉變為即時通訊

來源:互聯網
上載者:User

很多系統在實現原型時,由於初期對執行效率、處理速度等方面沒有苛刻的要求,都會設計成輪詢的模型。

而當我們實現完輪詢的架構後,可能由於各種需求,需要將系統整體的響應速度縮短。於是我們需要考慮,如何將輪詢的機制變為即時通知呢?(具體的應用比如參考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 PushClientManagermanager = 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 socketimport timeimport threadingBUFFERSIZE = 1024*20CMD_END_TAG = "#EndOfCmd#"taskmutex = threading.Event()reconnect_interval = 10 #you can set thisclass 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()

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.