精品伊人久久大香线蕉,开心久久婷婷综合中文字幕,杏田冲梨,人妻无码aⅴ不卡中文字幕

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
WebSocket的簡單介紹及應用

定時刷新的不足與改進

web開發中可能遇到這樣的場景:網頁里的某一塊區域里寫了一些內容,但這些內容不是固定的,即使看網頁的人沒有做任何操作,它們也會隨時間不斷變化。股票行情、活動或游戲的榜單都是比較常見的例子。

對此,一般的做法是用 setTimeout()setInverval() 定時執行任務,任務內容是Ajax訪問一次服務器,并在成功拿到返回數據后去更新頁面。

這種定時刷新的做法會有這樣一些感覺不足的地方:

  • 頻繁的定時網絡請求對瀏覽器(客戶端)和服務器來說都是一種負擔,尤其是當網頁里有多個定時刷新區域的時候。
  • 某幾次的定時任務可能是不必要的,因為服務器可能并沒有新數據,還是返回了和上一次一樣的內容。
  • 頁面內容可能不夠新,因為服務器可能剛更新了數據,但下一輪定時任務還沒有開始。

造成這些不足的原因歸結起來,主要還是由于服務器的響應總是被動的。HTTP協議限制了一次通信總是由客戶端發起請求,再由服務器端來返回響應。

因此,如果讓服務器端也可以主動發送信息到客戶端,就可以很大程度改進這些不足。WebSocket就是一個實現這種雙向通信的新協議。

WebSocket是基于HTTP的功能追加協議

WebSocket最初由html5提出,但現在已經發展為一個獨立的協議標準。WebSocket可以分為協議( Protocol )和 API 兩部分,分別由 IETF 和W3C制定了標準。

先來看看WebSocket協議的建立過程。

為了實現WebSocket通信,首先需要客戶端發起一次普通HTTP請求(也就是說,WebSocket的建立是依賴HTTP的)。請求報文可能像這樣:

GET ws://websocket.example.com/ HTTP/1.1Host: websocket.example.comUpgrade: websocketConnection: UpgradeOrigin: http://example.comSec-WebSocket-Key:pAloKxsGSHtpIHrJdWLvzQ==Sec-WebSocket-Version:13

其中HTTP頭部字段 Upgrade: websocketConnection: Upgrade 很重要,告訴服務器通信協議將發生改變,轉為WebSocket協議。支持WebSocket的服務器端在確認以上請求后,應返回狀態碼為 101 Switching Protocols 的響應:

HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: nRu4KAPUPjjWYrnzxDVeqOxCvlM=

其中字段 Sec-WebSocket-Accept 是由服務器對前面客戶端發送的 Sec-WebSocket-Key 進行確認和加密后的結果,相當于一次驗證,以幫助客戶端確信對方是真實可用的WebSocket服務器。

驗證通過后,這個握手響應就確立了WebSocket連接,此后,服務器端就可以主動發信息給客戶端了。此時的狀態比較像服務器端和客戶端接通了電話,無論是誰有什么信息想告訴對方,開口就好了。

一旦建立了WebSocket連接,此后的通信就不再使用HTTP了,改為使用WebSocket獨立的數據幀(這個幀有辦法看到,見后文)。

整個過程像這樣:

簡單的應用示例

應用WebSocket有這樣幾件事要做:

服務器端

以Node的服務器為例,我們使用 ws 這個組件,這樣搭建一個支持WebSocket的服務器端:

var request = require("request");var dateFormat = require("dateformat");var WebSocket = require("ws"),    WebSocketServer = WebSocket.Server,    wss = new WebSocketServer({        port: 8080,        path: "/guest"    });// 收到來自客戶端的連接請求后,開始給客戶端推消息wss.on("connection", function(ws) {    ws.on("message", function(message) {        console.log("received: %s", message);    });    sendGuestInfo(ws);});function sendGuestInfo(ws) {    request("http://uinames.com/api?region=china",        function(error, response, body) {            if (!error && response.statusCode === 200) {                var jsonObject = JSON.parse(body),                    guest = jsonObject.name + jsonObject.surname,                    guestInfo = {                        guest: guest,                        time: dateFormat(new Date(), "HH:MM:ss")                    };                if (ws.readyState === WebSocket.OPEN) {                    // 發,送                    ws.send(JSON.stringify(guestInfo));                    // 用隨機來“裝”得更像不定時推送一些                    setTimeout(function() {                        sendGuestInfo(ws);                    }, (Math.random() * 5 + 3) * 1000);                }            }        });}

這個例子使用了姓名生成站點 uinames 的API服務,來生成 {guest: "人名", time: "15:26:01"} 這樣的數據。函數 sendGuestInfo() 會不定時執行,并把包含姓名和時間的信息通過 send() 方法發送給客戶端。另外,注意 send() 方法需要以字符串形式來發送json數據。

這就像是服務器自己在做一些事,然后在需要的時候會通知客戶端一些信息。

客戶端

客戶端我們使用原生javascript來完成(僅支持WebSocket的瀏覽器):

var socket = new WebSocket("ws://localhost:8080/guest");socket.onopen = function(openEvent) {    console.log("WebSocket conntected.");};socket.onmessage = function(messageEvent) {    var data = messageEvent.data,        dataObject = JSON.parse(data);    console.log("Guest at " + dataObject.time + ": " + dataObject.guest);};socket.onerror = function(errorEvent) {    console.log("WebSocket error: ", errorEvent);};socket.onclose = function(closeEvent) {    console.log("WebSocket closed.");};

WebSocket的URL格式是 ws://wss:// 。因此,需要注意下URL地址的寫法,這也包括注意WebSocket服務器端的路徑(如這里的 /guest )等信息。因為是本地的示例所以這里是 localhost

客戶端代碼的流程很簡單:創建 WebSocket 對象,然后指定 onopenonmessage 等事件的回調即可。其中 onmessage 是客戶端與服務器端通過WebSocket通信的關鍵事件,想要在收到服務器通知后做點什么,寫在 onmessage 事件的回調函數里就好了。

效果及分析

通過 node server (假定服務器端的文件名為 server.js )啟動WebSocket服務器后,用瀏覽器打開一個引入了前面客戶端代碼的html(直接文件路徑 file:/// 就可以),就可以得到像這樣的結果:

聯系前面客戶端的代碼可以想到,實際從創建 WebSocket 對象的語句開始,連接請求就會發送,并很快建立起WebSocket連接(不出錯誤的話),此后就可以收到來自服務器端的通知。如果此時客戶端還想再告訴服務器點什么,這樣做:

socket.send("Hello, server!");

服務器就可以收到:

當然,這也是因為前面服務器端的代碼內同樣設置了 message 事件的回調。在這個客戶端和服務器都是javascript的例子中,無論是服務器端還是客戶端,都用 send() 發送信息,都通過 message 事件設置回調,形式上可以說非常一致。

其他可用的數據類型

WebSocket的 send() 可以發送的消息,除了前面用的字符串類型之外,還有兩種可用,它們是 BlobArrayBuffer

它們都代表二進制數據,可用于原始文件數據的發送。比如,這是一個發送Blob類型數據以完成向服務器上傳圖片的例子:

var fileEl = document.getElementById("image_upload");var file = fileEl.files[0];socket.send(file);

然后服務器端可以這樣把文件保存下來:

var fs = require("fs");wss.on("connection", function(ws) {    ws.on("message", function(message) {        fs.writeFile("upload.png", message, "binary", function(error) {            if (!error) {                console.log("File saved.");            }        });    });});

在客戶端接收二進制數據時,需注意WebSocket對象有一個屬性 binaryType ,初始值為 "blob" 。因此,如果接收的二進制數據是 ArrayBuffer ,應在接收之前這樣做:

socket.binaryType = "arraybuffer";

其他WebSocket服務器端

其他語言來做WebSocket服務器是怎樣的呢?下面是一個php的WebSocket服務器的例子(使用 Ratchet ):

<?phpuse Ratchet\ConnectionInterface;use Ratchet\MessageComponentInterface;require __DIR__ . '/vendor/autoload.php';class GuestServer implements MessageComponentInterface {    public function onOpen(ConnectionInterface $conn) {        $conn->send('The server is listening to you now.');    }    public function onMessage(ConnectionInterface $conn, $msg) {        $conn->send($this->generateGuestInfo());    }    public function onClose(ConnectionInterface $conn) {    }    public function onError(ConnectionInterface $conn, \Exception $e) {        $conn->close();    }    private function generateGuestInfo() {        $jsonString = file_get_contents('http://uinames.com/api?region=china');        $jsonObject = json_decode($jsonString, true);        $guest = $jsonObject['name'] . $jsonObject['surname'];        $guestInfo = array(            'guest' => $guest,            'time' => date('H:i:s', time()),        );        return json_encode($guestInfo);    }}$app = new Ratchet\App('localhost', 8080);$app->route('/guest', new GuestServer(), array('*'));$app->run();?>

這個例子也同樣是由服務器返回 {guest: "人名", time: "15:26:01"} 的json數據,不過由于php不像Node那樣可以用 setTimeout() 很容易地實現異步定時任務,這里改為在客戶端發送一次任意信息后,再去uinames取得信息并返回。

也可以看到,php搭建的WebSocket服務器仍然是近似的,主要通過WebSocket的 openmessage 等事件來實現功能。

在Chrome開發工具中查看WebSocket數據幀

Chrome開發工具中選擇Network,然后找到WebSocket的那個請求,里面可以選擇Frames。在Frames里看到的,就是WebSocket的數據幀了:

可以看到很像聊天記錄,其中用淺綠色標注的是由客戶端發送給服務器的部分。

結語

總的來說,把服務器和客戶端拉到了一個聊天窗口來辦事,這確實是很棒的想法。

即使只從形式上說,WebSocket的事件回調感覺也比定時任務用起來要更親切一些。

============================================

WebSocket

編輯鎖定
WebSocket protocol 是HTML5一種新的協議。它實現了瀏覽器與服務器全雙工通信(full-duplex)。
外文名
WebSocket
解    釋
HTML5一種新的協議
優    點
服務器可以主動傳送數據給客戶端
功    能
實現了瀏覽器與服務器全雙工通信

背景

編輯
在瀏覽器中通過http僅能實現單向的通信,comet可以一定程度上模擬雙向通信,但效率較低,并需要服務器有較好的支持; flash中的socket和xmlsocket可以實現真正的雙向通信,通過 flex ajax bridge,可以在javascript中使用這兩項功能. 可以預見,如果websocket一旦在瀏覽器中得到實現,將會替代上面兩項技術,得到廣泛的使用.面對這種狀況,HTML5定義了WebSocket協議,能更好的節省服務器資源和帶寬并達到實時通訊。
在JavaEE7中也實現了WebSocket協議。

原理

編輯
WebSocket protocol 。
現很多網站為了實現即時通訊,所用的技術都是輪詢(polling)。輪詢是在特定的的時間間隔(如每1秒),由瀏覽器對服務器發出HTTP request,然后由服務器返回最新的數據給客戶端的瀏覽器。這種傳統的HTTP request 的模式帶來很明顯的缺點 – 瀏覽器需要不斷的向服務器發出請求,然而HTTP request 的header是非常長的,里面包含的有用數據可能只是一個很小的值,這樣會占用很多的帶寬。
而比較新的技術去做輪詢的效果是Comet – 用了AJAX。但這種技術雖然可達到全雙工通信,但依然需要發出請求。
在 WebSocket API,瀏覽器和服務器只需要做一個握手的動作,然后,瀏覽器和服務器之間就形成了一條快速通道。兩者之間就直接可以數據互相傳送。在此WebSocket 協議中,為我們實現即時服務帶來了兩大好處:
1. Header
互相溝通的Header是很小的-大概只有 2 Bytes
2. Server Push

握手協議

編輯
在實現websocket連線過程中,需要通過瀏覽器發出websocket連線請求,然后服務器發出回應,這個過程通常稱為“握手” (handshaking)。
PS1:握手協議在后期的版本中,會標明版本編號,下面的例子屬于早期的協定之一,對于新版的 chrome 和 Firefox 皆不適用。
PS2:后期的版本大多屬于功能上的擴充,例如使用第7版的握手協議同樣也適用于第8版的握手協議。
例子:
瀏覽器請求
GET /demo HTTP/1.1
Host: 你的網址.com
Connection: Upgrade
Sec-WebSocket-Key2: 12998 5 Y3 1 .P00
Upgrade: WebSocket
Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5
Origin: http://你的網址.com
^n:ds[4U
//2010年之后的新版本websocket協議的Sec-WebSocket-Key只有一個,新的瀏覽只支持一個的,google的phpwebsocket用的是之前的協議所以不能直接運行通過,現在有個新版本是基于這個協議的是php-websocket-server-1
服務器回應
HTTP/1.1 101
WebSocket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
Sec-WebSocket-Origin: http://你的網址.com
Sec-WebSocket-Location: ws://你的網址.com/demo
Sec-WebSocket-Protocol: sample
8jKS’y:G*Co,Wxa-

瀏覽器

編輯
實現了websocket的瀏覽器:
Chrome
Supported in version 4+
Firefox
Supported in version 4+
Internet Explorer
Supported in version 10+
Opera
Supported in version 10+
Safari
Supported in version 5+

服務器

編輯
在服務器端,也出現了一些實現websocket協議的項目:
jetty 7.0.1 包含了一個初步的實現
resin 包含有websocket 實現
pywebsocket, apache http server 擴展
apache tomcat 7.0.27 版本
Nginx 1.3.13 版本
jWebSocket java實現版
websocket api在瀏覽器端的廣泛實現似乎只是一個時間問題了, 值得注意的是服務器端沒有標準的api, 各個實現都有自己的一套api, 并且jcp也沒有類似的提案, 所以使用websocket開發服務器端有一定的風險.可能會被鎖定在某個平臺上或者將來被迫升級.
本站僅提供存儲服務,所有內容均由用戶發布,如發現有害或侵權內容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
WebSocket使用
HTML5服務器推送消息的各種解決辦法
WebSocket
全雙工通信的 WebSocket
WebSocket 淺析
一文吃透 WebSocket 原理
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯系客服!

聯系客服

主站蜘蛛池模板: 墨玉县| 大冶市| 阿拉尔市| 安化县| 连城县| 辰溪县| 宝应县| 高陵县| 锦屏县| 永嘉县| 仁寿县| 全椒县| 平乐县| 绩溪县| 镇康县| 永和县| 自贡市| 舒兰市| 汝阳县| 永靖县| 三河市| 社旗县| 名山县| 读书| 香河县| 新巴尔虎右旗| 汝阳县| 顺昌县| 宜城市| 龙川县| 神木县| 西藏| 曲阳县| 肇源县| 勃利县| 扎鲁特旗| 天台县| 肇东市| 离岛区| 乌鲁木齐县| 右玉县|