WebSocket教程

一、為什么需要 WebSocket?

初次接觸 WebSocket 的人,都會問同樣的問題:我們已經有了 HTTP 協議,為什么還需要另一個協議?它能帶來什么好處?

答案很簡單,因為 HTTP 協議有一個缺陷:通信只能由客戶端發起。

舉例來說,我們想了解今天的天氣,只能是客戶端向服務器發出請求,服務器返回查詢結果。HTTP 協議做不到服務器主動向客戶端推送信息。

?

這種單向請求的特點,注定了如果服務器有連續的狀態變化,客戶端要獲知就非常麻煩。我們只能使用"輪詢":每隔一段時候,就發出一個詢問,了解服務器有沒有新的信息。最典型的場景就是聊天室。

輪詢的效率低,非常浪費資源(因為必須不停連接,或者 HTTP 連接始終打開)。因此,工程師們一直在思考,有沒有更好的方法。WebSocket 就是這樣發明的。

?

二、簡介

WebSocket 協議在2008年誕生,2011年成為國際標準。所有瀏覽器都已經支持了。

它的最大特點就是,服務器可以主動向客戶端推送信息,客戶端也可以主動向服務器發送信息,是真正的雙向平等對話,屬于服務器推送技術的一種。

其他特點包括:

(1)建立在 TCP 協議之上,服務器端的實現比較容易。

(2)與 HTTP 協議有著良好的兼容性。默認端口也是80和443,并且握手階段采用 HTTP 協議,因此握手時不容易屏蔽,能通過各種 HTTP 代理服務器。

(3)數據格式比較輕量,性能開銷小,通信高效。

(4)可以發送文本,也可以發送二進制數據。

(5)沒有同源限制,客戶端可以與任意服務器通信。

(6)協議標識符是ws(如果加密,則為wss),服務器網址就是 URL。


ws://example.com:80/some/path

?

三、客戶端的簡單示例

WebSocket 的用法相當簡單。

下面是一個網頁腳本的例子(點擊這里看運行結果),基本上一眼就能明白。


var ws = new WebSocket("wss://echo.websocket.org");ws.onopen = function(evt) { console.log("Connection open ..."); ws.send("Hello WebSockets!");
};ws.onmessage = function(evt) {console.log( "Received Message: " + evt.data);ws.close();
};ws.onclose = function(evt) {console.log("Connection closed.");
};      

?

四、客戶端的 API

WebSocket 客戶端的 API 如下。

4.1 WebSocket 構造函數

WebSocket 對象作為一個構造函數,用于新建 WebSocket 實例。


var ws = new WebSocket('ws://localhost:8080');

執行上面語句之后,客戶端就會與服務器進行連接。

實例對象的所有屬性和方法清單,參見這里。

4.2 webSocket.readyState

readyState屬性返回實例對象的當前狀態,共有四種。

  • CONNECTING:值為0,表示正在連接。
  • OPEN:值為1,表示連接成功,可以通信了。
  • CLOSING:值為2,表示連接正在關閉。
  • CLOSED:值為3,表示連接已經關閉,或者打開連接失敗。

下面是一個示例。


switch (ws.readyState) {case WebSocket.CONNECTING:// do somethingbreak;case WebSocket.OPEN:// do somethingbreak;case WebSocket.CLOSING:// do somethingbreak;case WebSocket.CLOSED:// do somethingbreak;default:// this never happensbreak;
}

4.3 webSocket.onopen

實例對象的onopen屬性,用于指定連接成功后的回調函數。


ws.onopen = function () {ws.send('Hello Server!');
}

如果要指定多個回調函數,可以使用addEventListener方法。


ws.addEventListener('open', function (event) {ws.send('Hello Server!');
});

4.4 webSocket.onclose

實例對象的onclose屬性,用于指定連接關閉后的回調函數。


ws.onclose = function(event) {var code = event.code;var reason = event.reason;var wasClean = event.wasClean;// handle close event
};ws.addEventListener("close", function(event) {var code = event.code;var reason = event.reason;var wasClean = event.wasClean;// handle close event
});

4.5 webSocket.onmessage

實例對象的onmessage屬性,用于指定收到服務器數據后的回調函數。


ws.onmessage = function(event) {var data = event.data;// 處理數據
};ws.addEventListener("message", function(event) {var data = event.data;// 處理數據
});

注意,服務器數據可能是文本,也可能是二進制數據(blob對象或Arraybuffer對象)。


ws.onmessage = function(event){if(typeof event.data === String) {console.log("Received data string");}if(event.data instanceof ArrayBuffer){var buffer = event.data;console.log("Received arraybuffer");}
}

除了動態判斷收到的數據類型,也可以使用binaryType屬性,顯式指定收到的二進制數據類型。


// 收到的是 blob 數據
ws.binaryType = "blob";
ws.onmessage = function(e) {console.log(e.data.size);
};// 收到的是 ArrayBuffer 數據
ws.binaryType = "arraybuffer";
ws.onmessage = function(e) {console.log(e.data.byteLength);
};

4.6 webSocket.send()

實例對象的send()方法用于向服務器發送數據。

發送文本的例子。


ws.send('your message');

發送 Blob 對象的例子。


var file = document.querySelector('input[type="file"]').files[0];
ws.send(file);

發送 ArrayBuffer 對象的例子。


// Sending canvas ImageData as ArrayBuffer
var img = canvas_context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img.data.length);
for (var i = 0; i < img.data.length; i++) {binary[i] = img.data[i];
}
ws.send(binary.buffer);

4.7 webSocket.bufferedAmount

實例對象的bufferedAmount屬性,表示還有多少字節的二進制數據沒有發送出去。它可以用來判斷發送是否結束。


var data = new ArrayBuffer(10000000);
socket.send(data);if (socket.bufferedAmount === 0) {// 發送完畢
} else {// 發送還沒結束
}

4.8 webSocket.onerror

實例對象的onerror屬性,用于指定報錯時的回調函數。


socket.onerror = function(event) {// handle error event
};socket.addEventListener("error", function(event) {// handle error event
});

?

五、服務端的實現

WebSocket 服務器的實現,可以查看維基百科的列表。

常用的 Node 實現有以下三種。

  • μWebSockets
  • Socket.IO
  • WebSocket-Node

具體的用法請查看它們的文檔,這里不詳細介紹了。

?

六、WebSocketd

下面,我要推薦一款非常特別的 WebSocket 服務器:Websocketd。

它的最大特點,就是后臺腳本不限語言,標準輸入(stdin)就是 WebSocket 的輸入,標準輸出(stdout)就是 WebSocket 的輸出。

舉例來說,下面是一個 Bash 腳本counter.sh


#!/bin/bashecho 1
sleep 1echo 2
sleep 1echo 3

命令行下運行這個腳本,會輸出1、2、3,每個值之間間隔1秒。


$ bash ./counter.sh
1
2
3

現在,啟動websocketd,指定這個腳本作為服務。


$ websocketd --port=8080 bash ./counter.sh

上面的命令會啟動一個 WebSocket 服務器,端口是8080。每當客戶端連接這個服務器,就會執行counter.sh腳本,并將它的輸出推送給客戶端。


var ws = new WebSocket('ws://localhost:8080/');ws.onmessage = function(event) {console.log(event.data);
};

上面是客戶端的 JavaScript 代碼,運行之后會在控制臺依次輸出1、2、3。

有了它,就可以很方便地將命令行的輸出,發給瀏覽器。


$ websocketd --port=8080 ls

上面的命令會執行ls命令,從而將當前目錄的內容,發給瀏覽器。使用這種方式實時監控服務器,簡直是輕而易舉(代碼)。

更多的用法可以參考官方示例。

  • Bash 腳本讀取客戶端輸入的例子
  • 五行代碼實現一個最簡單的聊天服務器

websocketd 的實質,就是命令行的 WebSocket 代理。只要命令行可以執行的程序,都可以通過它與瀏覽器進行 WebSocket 通信。下面是一個 Node 實現的回聲服務greeter.js


process.stdin.setEncoding('utf8');process.stdin.on('readable', function() {var chunk = process.stdin.read();if (chunk !== null) {process.stdout.write('data: ' + chunk);}
});

啟動這個腳本的命令如下。


$ websocketd --port=8080 node ./greeter.js

官方倉庫還有其他各種語言的例子。

?

七、參考鏈接

  • How to Use WebSockets
  • WebSockets - Send & Receive Messages
  • Introducing WebSockets: Bringing Sockets to the Web

(完)

?

原文鏈接:http://www.ruanyifeng.com/blog/2017/05/websocket.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/282234.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/282234.shtml
英文地址,請注明出處:http://en.pswp.cn/news/282234.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C# WPF十個美觀的界面設計展示

概述很多時候&#xff0c;我們設計的界面總是感覺缺乏美感&#xff0c;不是我們不會開發好看的界面&#xff0c;而是不知道怎么才算美觀&#xff0c;這時候我們不妨看看別人好的頁面是怎么做的.下面展示一些我覺得做的比較好的cs界面&#xff0c;希望能給大家在平時做界面設計時…

BZOJ3172: [Tjoi2013]單詞

【傳送門&#xff1a;BZOJ3172】 簡要題意&#xff1a; 給出n個單詞&#xff0c;你可以理解為將這些單詞變成一個個段落&#xff0c;然后求出每個單詞在所有段落中出現的次數 題解&#xff08;一&#xff09;&#xff1a; 剛開始不是很懂題目&#xff0c;結果發現將所有單詞看成…

MySQL5.6二進制軟件包編譯安裝詳解(三)

一、軟件環境 [rootlocalhost ~]# uname -r 3.10.0-862.el7.x86_64 [rootlocalhost ~]# cat /etc/redhat-release CentOS Linux release 7.5.1804 (Core) 二、安裝部署過程詳解 MySQL安裝3種方式&#xff1a;1>rpm包安裝應用文件默認安裝在/usr/local 目錄下2>源碼編譯需…

Java反射學習總結五(Annotation(注解)-基礎篇)

Annotation(注解)簡單介紹&#xff1a; 注解大家印象最深刻的可能就是JUnit做單元測試,和各種框架里的使用了。本文主要簡介一下注解的用法&#xff0c;下篇文章再深入的研究。 annotation并不直接影響代碼語義。可是它可以被看作類似程序的工具或者類庫。它會反過來對正在執行…

使用autok3s 安裝k3s 集群 和 kuboard 管理集群

一、k3s介紹1.1 什么是k3s?k3s 是經過 CNCF 認證的由 Rancher 公司開發維護的一個輕量級的 Kubernetes 發行版&#xff0c;內核機制還是和 k8s 一樣&#xff0c;但是剔除了很多外部依賴以及 K8s 的 alpha、beta 特性&#xff0c;同時改變了部署方式和運行方式&#xff0c;目的…

Nginx—— Rewrite規則的使用

一、使用場景 1、URL訪問跳轉 &#xff08;1&#xff09;頁面跳轉 &#xff08;2&#xff09;兼容性支持&#xff08;比如新老版本交替時&#xff0c;給老版本一條訪問道路&#xff09; &#xff08;3&#xff09;展示效果&#xff08;比如縮短前臺界面的地址欄的url&#…

java對象實例化的方式

java對象實例化的方式有以下幾種&#xff1a;1、使用new2、工廠模式3、反射4、clone()方法5、反序列化方式 /** 實現Cloneable和Serializable接口 */public class Book implements Cloneable, Serializable {private static final long serialVersionUID 1L; private Integer …

iOS-生成二維碼圖片【附中間帶有小圖標二維碼】(QRCode)

生成二維碼圖片也是項目中常用到的&#xff0c;二維碼的掃描Git上有很多好用的&#xff0c;這里主要說下二維碼的生成 1.普通二維碼 方法 /**生成二維碼QRStering&#xff1a;字符串imageFloat&#xff1a;二維碼圖片大小*/ (UIImage *)createQRCodeWithString:(NSString *)QRS…

libubox

lbubox是openwrt的一個核心庫&#xff0c;封裝了一系列基礎實用功能&#xff0c;主要提供事件循環&#xff0c;二進制格式處理&#xff0c;linux鏈表實現和一些JSON輔助處理。 它的目的是以動態鏈接庫方式來提供可重用的通用功能&#xff0c;給其他模塊提供便利和避免再造輪子。…

社區糾紛不斷:程序員何苦為難程序員

出品 | OSC開源社區&#xff08;ID&#xff1a;oschina2013)今年年初&#xff0c;我們報道“因為被多人侮辱大吼&#xff0c;Swift 之父正式退出 Swift 核心團隊”。諸如此類的“語言暴力”、“網絡暴力”事件在開源社區乃至整個 IT 社區屢見不鮮。多個技術社區&#xff0c;都出…

PHP 分布式集群中session共享問題以及session有效期的設置

一、Session的原理 以下以默認情況舉例&#xff1a; session_start();之后&#xff0c;會生成一個唯一的session_id&#xff0c;每一個用戶對應唯一一個session_id&#xff0c;每一個session_id對應服務器端的一個session文件。這個session文件存儲著當前session_id的信息&am…

[SDOI2009]Bill的挑戰——全網唯一 一篇容斥題解

全網唯一一篇容斥題解 Description Solution 看到這個題&#xff0c;大部分人想的是狀壓dp 但是我是個蒟蒻沒想到&#xff0c;就用容斥切掉了。 并且復雜度比一般狀壓低&#xff0c; &#xff08;其實這個容斥的算法&#xff0c;提出來源于ywy_c_asm&#xff09; &#xff08;然…

[NOIP2015提高組]運輸計劃

題目&#xff1a;BZOJ4326、洛谷P2680、Vijos P1983、UOJ#150、codevs4632、codevs5440。 題目大意&#xff1a;有一棵帶權樹&#xff0c;有一些運輸計劃&#xff0c;第i個運輸計劃從ai到bi&#xff0c;耗時為ai到bi的距離&#xff0c;所有運輸計劃一起開始。現在可以把一條邊權…

對象存儲OSS服務

一、oss是什么 阿里云對象存儲服務&#xff08;Object Storage Service&#xff0c;簡稱OSS&#xff09;為您提供基于網絡的數據存取服務。使用OSS&#xff0c;您可以通過網絡隨時存儲和調用包括文本、圖片、音頻和視頻等在內的各種非結構化數據文件。 阿里云OSS將數據文件以…

《Access 2007開發指南(修訂版)》一一1.5 什么是數據庫對象

本節書摘來自異步社區出版社《Access 2007開發指南(修訂版)》一書中的第1章&#xff0c;第1.5節&#xff0c;作者&#xff1a; 【美】Alison Balter&#xff0c;更多章節內容可以訪問云棲社區“異步社區”公眾號查看。 1.5 什么是數據庫對象 Access 2007開發指南(修訂版)正如前…

ETL工具kettle的組件--生成記錄

今天介紹下kettle的一個比較實用的組件——生成記錄&#xff1b;當我們想將一部分文本數據變成數據行&#xff0c;每個字段作為一個數據行的一個列&#xff0c;那么我們可以利用這個組件&#xff1b;它的位置在雙擊點開根據自己的實際需要進行設置當設置后&#xff0c;可以點擊…

Linux學習筆記一

linux  kernel lib module shell tools ls -la&#xff1a; 顯示所有文件包括隱藏文件  cat /proc/cpuinfo&#xff1a; 顯示cpu信息 man man  /string&#xff1a; 向上搜索string字符串 繼續按下小寫n向上搜索  ?string&#xff1a; 向下搜索string字符串 繼續按下大…

PHP中路由和rewrite的使用

一、場景介紹&#xff1a; 1、簡化url地址&#xff0c;方便大家記憶 2、有利于搜索引擎優化 3、安全&#xff08;讓用戶看不出網站的目錄結構&#xff09; 舉例&#xff1a;比如我這里將main控制器中的bb方法路由到kk&#xff0c;這樣&#xff0c;我們a標簽請求跳轉到cp.xi…

《NoSQL權威指南》導讀

引言 NoSQL權威指南“沒有什么會比引入新秩序更難&#xff0c;因為創新者必須要面對那些在舊環境中已經做得很好的對手&#xff0c;以及那些在新環境中做得很好的冷漠者。” ——Niccolo Machiavelli [1] 在過去的幾十年&#xff0c;我已經通過Elsevier/Morgan Kaufmann出版社出…

zookeeper的單實例和偽集群部署

原文鏈接: http://gudaoyufu.com/?p1395 zookeeper工作方式 ZooKeeper 是一個開源的分布式協調服務&#xff0c;由雅虎創建&#xff0c;是 Google Chubby 的開源實現。 分布式應用程序可以基于 ZooKeeper 實現諸如數據發布/訂閱、負載均衡、命名服務、分布式協 調/通知、集群管…