最近有個管理系統項目用到了 websocket,而後我去看了下,這個東西,感受和socket 很像,三次握手。這個是能夠直接鏈接web 和服務端。java
具體差異和特色,再看看。git
下面是本人再別處copy過來轉載過來的,就當是本身學習過了。後面若是有用到也能夠及時翻看。github
業務場景: 當用戶D作一個插入或者更新操做時,這個時候,咱們要讓ABC用戶及時知道。web
技術實現:創建一個socket的長鏈接,像在用戶登錄就創建,而後發生D用戶操做便可通知ABC用戶。瀏覽器
技術特色:它是一個長鏈接,對服務器壓力會增大,若是是很是大的併發訪問,能夠想象一下服務器壓力,可是勝在及時性,能夠及時通知等操做。緩存
技術思考:我感受它就是一個socket,只是應用上面能夠對接web端。而後就是能夠對某些進行優化,應用場景上,分空閒時期或應用時期能夠對socket及時的關閉或者開啓,這樣可能會讓服務器壓力小一些。服務器
WebSocket用於在Web瀏覽器和服務器之間進行任意的雙向數據傳輸的一種技術。WebSocket協議基於TCP協議實現,包含初始的握手過程,以及後續的屢次數據幀雙向傳輸過程。其目的是在WebSocket應用和WebSocket服務器進行頻繁雙向通訊時,可使服務器避免打開多個HTTP鏈接進行工做來節約資源,提升了工做效率和資源利用率。websocket
1. 引言
互聯網發展的早期,網站上只是一些靜態展現頁面。用戶請求(Request)網站頁面,網站回覆(Response)頁面內容給用戶瀏覽器。由於需求簡單,因此也沒有很複雜的協議過程。這種形式的Request/Response交互流程以下圖所示:網絡
圖 11 Request/Responsesession
隨着互聯網技術的發展,帶寬逐步提升,用戶數也愈來愈龐大。對互聯網的呈現內容提出了要求,隨之出現了動態頁面技術,對同一個頁面,頁面的某些部分對不一樣的訪問用戶,呈現的內容不一樣。相關的實現技術有CGI、ASP、PHP、JSP等。因爲訪問量的增長,WEB服務器同時處理的用戶數也達到了萬(10K)以上級別,這就是C10K問題:"The C10K problem"[1]。爲了緩解服務器壓力,每次Request/Response後鏈接(TCP鏈接)繼續保持,以及對同一個TCP鏈接,屢次複用Request/Response的方法(也稱爲Pipeline)也提了出來。這就是HTTP/1.1協議中長鏈接的主要內容。
伴隨移動互聯網的發展,大量移動終端和其上的APP應用接入網絡,HTML5技術也提了出來,以便支持WEB上的音視頻播放、實時遊戲、實時聊天等。催生了這樣一個需求,當服務器有更新時,須要當即將數據發送給客戶端,這就是基於服務器端的推送技術。
WEBSOCKET以前的解決方法大概這麼幾種: 1)輪詢:客戶端設置一個時間間隔,時間到之後,向服務器發送request詢問有無新數據,服務器當即返回response,若是有更新則攜帶更新的數據。2)長鏈接(long poll): 和輪詢類似,可是爲阻塞模式的輪詢,客戶端請求新的數據request, 服務器會阻塞請求,直到有新數據後才返回response給客戶端;而後客戶端再重複此過程。這兩種方式的特色,不斷的創建HTTP鏈接,而後發送請求request,以後服務器等待處理。服務端體現的是一種被動性,同時這種處理方式,很是耗費網絡帶寬和服務器資源。
服務器向客戶端推送更新時,由於被動性,對低延遲的應用體驗很差;由於request/response的交互方式,對網絡帶寬和服務器帶來了額外的負擔(例如屢次請求的HTTP頭部, TCP鏈接複用會致使的Head-of-Line Blocking線頭阻塞[2]等)。若是在單一的TCP鏈接中,使用雙向通訊(全雙工通訊)就能很好的解決此問題。這就是WebSocket技術的原因。
2. WebSocket技術及協議
WebSocket技術的優勢有:1)經過第一次HTTP Request創建了鏈接以後,後續的數據交換都不用再從新發送HTTP Request,節省了帶寬資源; 2) WebSocket的鏈接是雙向通訊的鏈接,在同一個TCP鏈接上,既能夠發送,也能夠接收; 3)具備多路複用的功能(multiplexing),也即幾個不一樣的URI能夠複用同一個WebSocket鏈接。這些特色很是相似TCP鏈接,可是由於它借用了HTTP協議的一些概念,因此被稱爲了WebSocket。
2.1 WebSocket API
WebSocket API[3], 也稱爲WebSocket接口(Interface),定義了Web應用和服務器進行雙向通訊的公共接口。 以下圖所示:
圖 21 WebSocket API
接口的內容能夠分爲三類:狀態變量、網絡功能和消息處理等。
構造函數WebSocket(url, protocols):構造WebSocket對象,以及創建和服務器鏈接; protocols可選字段,表明選擇的子協議
狀態變量readyState: 表明當前鏈接的狀態,短整型數據,取值爲CONNECTING(值爲0), OPEN(值爲1), CLOSING(值爲2), CLOSED(值爲3)
方法變量close(code, reason): 關閉此WebSocket鏈接。
狀態變量bufferedAmount: send函數調用後,被緩存而且未發送到網絡上的數據長度
方法變量send(data): 將數據data經過此WebSocket發送到對端
回調函數onopen/onmessage/onerror/onclose: 當相應的事件發生時會觸發此回調函數
2.1.1 示例
客戶端使用例子(JavaScript):
var websocket = new WebSocket("ws://www.host.com/path");
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onclose = function(evt) { onClose(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) }; }
function onMessage(evt) { alert( evt.data); }
function onError(evt) { alert( evt.data); }
websocket.send("client to server");
2.2 WebSocket協議
WebSocket當作是一種相似TCP/IP的socket技術;此socket在Web應用中實現,並得到了和TCP/IP通訊同樣靈活方便的全雙向通訊功能。
WebSocket協議由RFC 6455定義。協議分爲兩個部分: 握手階段和數據通訊階段。
WebSocket爲應用層協議,其定義在TCP/IP協議棧之上。WebSocket鏈接服務器的URI以"ws"或者"wss"開頭。ws開頭的默認TCP端口爲80,wss開頭的默認端口爲443。
2.2.1 握手階段
客戶端和服務器創建TCP鏈接以後,客戶端發送握手請求,隨後服務器發送握手響應即完成握手階段。以下圖所示:
圖 22 Handshake
客戶端握手請求相似以下:
服務器的握手響應相似以下:
須要關閉鏈接時,任意一方直接發送類型爲關閉幀(Close frame)的控制幀數據給對方便可。
2.2.2 數據通訊
WebSocket的數據在發送時,被組織爲依次序的一串數據幀(data frame),而後進行傳送。
傳送的幀類型分爲兩類:數據幀(data frame)和控制幀(Control frame)。數據幀能夠攜帶文本數據或者二進制數據;控制幀包含關閉幀(Close frame)和Ping/Pong幀。
幀的格式以下所示:
其中最重要的字段爲opcode(4bit)和MASK(1bit):
MASK值,從客戶端進行發送的幀必須置此位爲1,從服務器發送的幀必須置爲0。若是任何一方收到的幀不符合此要求,則發送關閉幀(Close frame)關閉鏈接。
opcode的值: 0x1表明此幀爲文本數據幀, 0x2表明此幀爲二進制數據幀, 0x8爲控制幀中的鏈接關閉幀(close frame), 0x9爲控制幀中的Ping幀, 0xA(十進制的10)爲控制幀中的Pong幀。
Ping/Pong幀: Ping幀和Pong幀用於鏈接的保活(keepalive)或者診斷對端是否在線。這兩種幀的發送和接收不對WEB應用公開接口,由實現WebSocket協議的底層應用(例如瀏覽器)來實現它。
2.2.3 鏈接關閉
任何一端發送關閉幀給對方,便可關閉鏈接。關閉鏈接時一般都帶有關閉鏈接的狀態碼(status code)。常見狀態碼的含義以下:
1000 鏈接正常關閉
1001 端點離線,例如服務器down,或者瀏覽器已經離開此頁面
1002 端點由於協議錯誤而中斷鏈接
1003 端點由於受到不能接受的數據類型而中斷鏈接
1004 保留
1005 保留, 用於提示應用未收到鏈接關閉的狀態碼
1006 端點異常關閉
1007 端點收到的數據幀類型不一致而致使鏈接關閉
1008 數據違例而關閉鏈接
1009 收到的消息數據太大而關閉鏈接
1010 客戶端由於服務器未協商擴展而關閉
1011 服務器由於遭遇異常而關閉鏈接
1015 TLS握手失敗關閉鏈接
3. WebSocket示例
這裏以JAVA+Eclipse+TOMCAT+JDK8+瀏覽器,作爲例子。
具體代碼見github連接:https://github.com/siwind/HelloWebJava
以回聲服務器爲例,打開Eclipse,新建Web -- Dynamic Web Project項目,項目名稱"HelloWebJava"
3.1 WebSocket服務端
在項目中新建java類,採用註解的方式,實現OnOpen/OnClose/OnMessage回調方法便可。代碼以下:
import java.io.IOException;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/WSHello")
public class HelloEndPoint {
@OnOpen
public void onOpen(Session session){
System.out.println("Session " + session.getId() + " has opened a connection");
try {
session.getBasicRemote().sendText("Connection Established");
} catch (IOException ex) {
ex.printStackTrace();
}
}
@OnMessage
public void onMessage(String message, Session session){
System.out.println("Message from " + session.getId() + ": " + message);
try {
session.getBasicRemote().sendText(message);
} catch (IOException ex) {
ex.printStackTrace();
}
}
@OnClose
public void onClose(Session session){
System.out.println("Session " +session.getId()+" has closed!");
}
/**
* 注意: OnError() 只能出現一次. 其中的參數都是可選的。
* @param session
* @param t
*/
@OnError
public void onError(Session session, Throwable t) {
t.printStackTrace();
}
}
3.2 WebSocket瀏覽器客戶端
在項目的WebContent目錄下面,新建名稱爲index.htm的文件,內容以下(部分):
webSocket = new WebSocket(wsUri);
webSocket.onopen =function(event){
if(event.data === undefined)
return;
writeResponse(event.data);
};
webSocket.onmessage =function(event){
writeResponse(event.data);
};
webSocket.onerror =function(event){
writeResponse("<span style='color: red;'>ERROR: </span>Connection error! " + event.data);
};
webSocket.onclose =function(event){
writeResponse("<span style='color: blue;'>INFO: </span>Connection closed. code=" + event.code);
};
}
3.3 部署及運行
在JDK8環境下,部署到Tomcat8.0.x/Tomcat8.5.x/Wildfly10.x/Glassfish4.x,正常運行。以下圖所示:
圖 31 WebSocket Echo Example
4. 結論
WebSocket和傳統的HTTP交互方式的區別以下圖:
圖 41交互方式比較
WebSocket的結論以下:
基於TCP/IP協議實現
是一種全雙向的通訊, 具備底層socket的特色
節約帶寬,節省服務器資源
是HTML5的技術之一,具備巨大的應用前景
本文的完整示例代碼: https://github.com/siwind/HelloWebJava--------------------- 轉載:原文:https://blog.csdn.net/yinqingwang/article/details/52565133