websocket

WebSocket

1.長輪詢與websocket介紹
2.websocket編程

 

1.長輪詢與websocket介紹

長輪詢javascript

長久以來, 建立實現客戶端和用戶端之間雙工通信的web app都會形成HTTP輪詢的濫用: java

​ 客戶端向主機不斷髮送不一樣的HTTP呼叫來進行詢問。jquery

這會致使一系列的問題:web

  1. 服務器被迫爲每一個客戶端使用許多不一樣的底層TCP鏈接:一個用於向客戶端發送信息,其它用於接收每一個傳入消息。編程

  2. 有線協議有很高的開銷,每個客戶端和服務器之間都有HTTP頭。bootstrap

  3. 客戶端腳本被迫維護從傳出鏈接到傳入鏈接的映射來追蹤回覆。瀏覽器

一個更簡單的解決方案是使用單個TCP鏈接雙向通訊。 這就是WebSocket協議所提供的功能。 結合WebSocket APIWebSocket協議提供了一個用來替代HTTP輪詢實現網頁到遠程主機的雙向通訊的方法。服務器

webscoket介紹websocket

WebSocket協議是基於TCP的一種新的網絡協議。它實現了瀏覽器與服務器全雙工(full-duplex)通訊——容許服務器主動發送信息給客戶端。WebSocket通訊協議於2011年被IETF定爲標準RFC 6455,並被RFC7936所補充規範。cookie

在實現websocket連線過程當中,須要經過瀏覽器發出websocket連線請求,而後服務器發出迴應,這個過程一般稱爲「握手」 。在 WebSocket API,瀏覽器和服務器只須要作一個握手的動做,而後,瀏覽器和服務器之間就造成了一條快速通道。二者之間就直接能夠數據互相傳送。在此WebSocket協議中,爲咱們實現即時服務帶來了兩大好處:

  1. Header互相溝通的Header是很小的,大概只有 2 Bytes

  2. Server Push服務器的推送,服務器再也不被動的接收到瀏覽器的請求以後才返回數據,而是在有新數據時就主動推送給瀏覽器。

websocket的創建過程

瀏覽器請求:

GET /webfin/websocket/ HTTP/1.1  # HTTP請求方式
Host: localhost   #
Origin: http://服務器地址    #
Cookie:_aaa   # cookie
#如下是創建webscoket鏈路的核心。  
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==   # 密鑰
Sec-WebSocket-Version: 13            # websocket版本

服務器迴應

HTTP/1.1 101 Switching Protocols
...

Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: K7D JLdLooIwIG/MOpvWFB3y3FE8=

WebSocket借用http請求進行握手,相比正常的http請求,多了一些內容。其中:
Upgrade: websocket
Connection: Upgrade
表示但願將http協議升級到Websocket協議。

Sec-WebSocket-Key是瀏覽器隨機生成的base64 encode的值,用來詢問服務器是不是支持WebSocket。
服務器返回:
Upgrade: websocket
Connection: Upgrade

告訴瀏覽器即將升級的是Websocket協議.
Sec-WebSocket-Accept是將請求包「Sec-WebSocket-Key」的值,與」258EAFA5-E914-47DA-95CA-C5AB0DC85B11″這個字符串進行拼接,而後對拼接後的字符串進行sha-1運算,再進行base64編碼獲得的。用來講明本身是WebSocket助理服務器。

Sec-WebSocket-Version是WebSocket協議版本號。RFC6455要求使用的版本是13,以前草案的版本均應當被棄用。
更多握手規範詳見RFC6455。

 

2. websocket編程

websocket的編程分爲服務端編程和客戶端編程。

服務端編程

Tornado定義了 tornado.websocket.WebSocketHandler 類用於處理 WebSocket 連接的請求,應用開發者應該繼承該類並實現其中的open()、on_message()、on_close() 函數。

除了這3個 Tornado 框架自動調用的入口函數,WebSocketHandler 還提供了兩個開發者主動操做 WebSocket的函數。

  • WebSocketHandler.write_message(message)函數:用於向與本連接相對應的客戶端寫消息

  • WebSocketHandler.close(code=None,reason=None)函數:主動關閉 WebSocket連接。其中的code和reason用於告訴客戶端連接被關閉的緣由。參數code必須是一個數值,而reason是一個字符串。


class BaseWebSocketHandler(tornado.websocket.WebSocketHandler,SessionMixin):
   def get_current_user(self):
       # current_user = self.get_secure_cookie('ID')
       current_user = self.session.get('user')
       if current_user:
           return current_user
       return None

class MessageWSHandler(BaseWebSocketHandler):
   users = set()

   def open(self):
       # 有新的websocket連接時調用這個函數
       MessageWSHandler.users.add(self)
       print('-------------------open-----------------')

   def on_message(self, message):
       print(message,self.current_user)
       for u in self.users:
           u.write_message('%s-%s-說:%s'%(self.current_user.username,datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),message))

   def on_close(self):
       print('-------------------on_close-----------------')
       # 當websocket連接關閉時調用這個函數
       if self in MessageWSHandler.users:
           MessageWSHandler.users.remove(self)
       print(MessageWSHandler.users)

 

客戶端編程

因爲 WebSocket 是 HTML5 的標準之一,因此主流瀏覽器的 web 客戶端編程語言 Javascript 已經支持 WebSocket 的客戶端編程。

客戶短編程圍繞着 WebSocket 對象展開,在 Javascript 中能夠經過以下代碼初始化 WebSocket 對象:


var socket = new WebSocket(url ):

在代碼中只需給 WebSocket構造函數傳入服務器的URL地址,能夠爲該對象的以下事件指定處理函數以響應它們。

  • WebSocket.onopen :此事件發生在 WebSocket 連接創建時

  • WebSocket.onmessage :此事件發生在收到了來自服務器的消息時

  • WebSocket.onclose :此事件發生在與服務器的連接關閉時

  • WebSocket.onerror :此事件發生在通訊過程當中有任何錯誤時

除了這些事件處理函數,還能夠經過 WebSocket 對象的兩個方法進行主動操做

  • WebSocket.send(data) :向服務器發送消息

  • WebSocket.close() :主動關閉現有連接

參考代碼以下:


<body>
 
   <div>
       <textarea id="text"></textarea>
       <a href="javascript:WebSocketTest();">發送</a>
   </div>
   <div id="messages" style="height:500px;overflow: auto;"></div>
 
<script src="{{static_url('js/jquery-2.2.0.min.js')}}"></script>
<!--<script src="{{static_url('js/bootstrap.min.js')}}"></script>-->
 
   <script type="text/javascript">
       var mes = document.getElementById('messages');
       function WebSocketTest() {
           if("WebSocket" in window){
               mes.innerHTML = "發送Websocket請求成功!";
               var ws = new WebSocket("ws://127.0.0.1:8000/websocket");
               ws.onopen = function () {
                   ws.send($("#text").val()) ;
              };
               ws.onmessage = function (evt) {
                   var received_msg = evt.data;
                   mes.innerHTML = mes.innerHTML +
                           "<br>服務器已收到信息:<br>" + received_msg;
              };
               ws.onclose = function () {
                 mes.innerHTML = mes.innerHTML + "<br>鏈接已經關閉...";
              };
          } else {
               mes.innerHTML = "發送Websocket請求失敗!";
          }
      }
   </script>
</body>
相關文章
相關標籤/搜索