Web即時通信
所謂Web即時通信,就是說我們可以通過一種機制在網頁上立即通知用戶一件事情的發生,是不需要用戶刷新網頁的。Web即時通信的用途有很多,比如實時聊天,即時推送等。如當我們在登陸瀏覽 知乎時如果有人回答了我們的問題,知乎就會即時提醒我們,再比如現在電子商務的在線客服功能。這些能大大提高用戶體驗的功能都是基于Web即時通信實現的。
而由于HTTP請求是無狀態的,也就是說每次請求完成后,HTTP鏈接就斷開了,服務器和瀏覽器互相之間是完全不可知的,只有下一次再發起一次請求 才能更新相應的信息。談到這里我們就不難想到,我們可以簡單的讓瀏覽器每隔一個周期就發起一次請求,這樣就能在一定程度上模擬實時效果了,這也就是輪訓,術語叫做Polling。
通過輪訓的方式我們就可以相對即時的獲取信息。但是由于輪訓的原理是使瀏覽器頻繁的向服務器發起請求,這在一定程度上會造成性能效率問題。為了優化 這些性能問題,人們又想到了一種方法。那就是在服務器接收到請求的時候不理解返回,而是只有當有數據變化(或者超時)的時候才返回。這樣一來,我們就可以 利用一次請求最大可能的保持連接的有效性,大大的減少了Polling中的請求次數。這個方法叫做長輪訓,也叫做Long-Polling。
以上方法是實現Web實時通信的常用方法。當然在HTML5出來之后,我們就有更好的選擇啦。在HTML5中,我們可以使用SSE或者是WebSocket。SSE的全稱是Server Send Event,聽名字就很好理解啦。也就是由服務器來推送數據。看到這里是不是興奮呢?其實很多情況下,我們只需要這種簡單的功能:由服務器推送數據到瀏覽器。比如推送比賽信息、股價的變化等等。
如果SSE還不能滿足我們的需求的話,我們完全就可以使用WebSocket啦。當使用WebSocket時,瀏覽器和服務器之間就建立了一個全雙工通道,互相都可以發送消息,完全的做到了及時,就像使用tcp socket一樣。
到這里我們就基本了解了一些事先Web實時通信的機制,下一節中,我們將使用SSE實現一個簡單的在線聊天室。
SSE的在線聊天室的實現在線聊天室推送消息有很多種方式,在這門課程中我們使用SSE來實現。為了方便接收消息,我們借助Redis的pub/sub功能來接收和發送消息。Web服務器端我們將使用Flask實現。如果對Flask不是很熟悉,也可以在實驗樓學習相關的Flask課程。(http://www.shiyanlou.com/)
SSE 的工作方式在上面的課程中,我們了解到SSE是基于HTTP實現的,那么瀏覽器怎么樣知道這是一個服務器事件流呢?其實很簡單啦,就是將HTTP的頭部Content-Type設置成text/event-stream就可以了。其實SSE,就是瀏覽器向服務器發送一個HTTP請求,然后服務器不斷單向地向瀏覽器推送"信息",這些信息的格式也非常簡單,就是前綴data:加上發送的數據內容,然后以/n/n結尾。
Redis中的訂閱功能Redis是很流行的一個內存數據庫,可以用于實現緩存,隊列等服務。在這門項目課程中我們將使用的Redis的發布/訂閱功 能。簡單來說,我們所謂訂閱功能就是我們可以訂閱一些頻道,然后當這些頻道有新的消息的時候我們就可以自動接收這些信息。當服務器接收到瀏覽器POST過 來的消息的時候,會將這些信息發布到特定的頻道中。接著我們之前訂閱了這些頻道的客戶端就回自動收到這些消息,最后我們就將這些消息通過SSE推送到客戶端。
經過上面的分析,整個聊天室的流程已經很清晰啦。下面通過源代碼注釋的方式進行分析吧。在/home/shiyanlou目錄下,創建目錄code,然后在該目錄下創建源文件app.py
# 消息生成器def event_stream(): pubsub = r.pubsub() # 訂閱'chat'頻道 pubsub.subscribe('chat') # 開始監聽消息,如果有消息產生在返回消息 for message in pubsub.listen(): PRint message # Server-Send Event的數據格式以'data:'開始 yield 'data: %s/n/n' % message['data']# 登陸函數,首次訪問需要登陸@app.route('/login', methods=['GET', 'POST'])def login(): if flask.request.method == 'POST': # 將用戶信息記錄到session中 flask.session['user'] = flask.request.form['user'] return flask.redirect('/') return '<form action="" method="post">user: <input name="user">'# 接收Javascript post過來的消息@app.route('/post', methods=['POST'])def post(): message = flask.request.form['message'] user = flask.session.get('user', 'anonymous') now = datetime.datetime.now().replace(microsecond=0).time() # 將消息發布到'chat'頻道中 r.publish('chat', u'[%s] %s: %s' % (now.isoformat(), user, message))return flask.Response(status=204)
詳細代碼請登錄實驗樓http://www.shiyanlou.com/courses/?course_type=project&tag=all
由于使用了Redis,所以需要安裝redis服務器,通過以下步驟就可以將redis服務器,以及相關的依賴包安裝好。
$ sudo apt-get update$ sudo apt-get install redis-server$ sudo service redis start$ sudo pip install redis$ sudo pip install flask
安裝完成以后,運行,然后通過瀏覽器訪問http://127.0.0.1:8989就看到效果啦.

另有其他項目課的詳細講解和內容歡迎登陸實驗樓http://www.shiyanlou.com/courses/?course_type=project&tag=all
官方網站:實驗樓 http://www.shiyanlou.com
新聞熱點
疑難解答