WebSocket協議屬於HTML5標準,愈來愈多瀏覽器已經原生支持WebSocket,它能讓客戶端和服務端實現雙向通訊。在客戶端和服務器端創建一條WebSocket鏈接後,服務器端消息可直接發送到客戶端,從而打破傳統的請求響應模式,避免了無心義的請求。好比傳統的方式可能會使用AJAX不斷請求服務器端,而WebSocket則能夠直接發送數據到客戶端且客戶端沒必要請求。同時,因爲有了瀏覽器的原生支持,編寫客戶端應用程序也變得更加便捷且沒必要依賴第三方插件。另外,WebSocket協議摒棄了HTTP協議繁瑣的請求頭,而是以數據幀的方式進行傳輸,效率更高。javascript
圖爲WebSocket協議通訊的過程,首先客戶端會發送一個握手包告訴服務器端我想升級成WebSocket,不知道你服務器端是否贊成,這時若是服務器端支持WebSocket協議則會返回一個握手包告訴客戶端沒問題,升級已確認。而後就成功創建起了一條WebSocket鏈接,該鏈接支持雙向通訊,而且使用WebSocket協議的數據幀格式發送消息。java
握手過程須要說明下,爲了讓WebSocket協議能和現有HTTP協議Web架構互相兼容,因此WebSocket協議的握手要基於HTTP協議,好比客戶端會發送相似以下的HTTP報文到服務器端請求升級爲WebSocket協議,其中包含的Upgrade: websocket就是告訴服務器端我想升級協議:web
GET ws://localhost:8080/hello HTTP/1.1
Origin: http://localhost:8080
Connection: Upgrade
Host: localhost:8080
Sec-WebSocket-Key: uRovscZjNol/umbTt5uKmw==
Upgrade: websocket
Sec-WebSocket-Version: 13複製代碼
此時若是服務器端支持WebSocket協議,則它會發送一個贊成客戶端升級協議的報文,具體報文相似以下,其中Upgrade: websocket就是告訴客戶端我贊成你升級協議:瀏覽器
HTTP/1.1 101 WebSocket Protocol Handshake
Date: Fri, 10 Feb 2016 17:38:18 GMT
Connection: Upgrade
Server: Kaazing Gateway
Upgrade: WebSocket
Sec-WebSocket-Accept: rLHCkw/SKsO9GAH/ZSFhBATDKrU=複製代碼
完成如上握手後,HTTP協議鏈接就被打破,接下去則是開始使用WebSocket協議進行雙方通訊,這條鏈接仍是原來的那條TCP/IP鏈接,端口也仍是原來的80或443。服務器
下面舉一個Tomcat中編寫WebSocket的簡單例子:websocket
public class HelloWebSocketServlet extends WebSocketServlet {
private static List<MessageInbound> socketList = new ArrayList<MessageInbound>();
protected StreamInbound createWebSocketInbound(String subProtocol,HttpServletRequest request){
return new WebSocketMessageInbound();
}
public class WebSocketMessageInbound extends MessageInbound{
protected void onClose(int status){
super.onClose(status);
socketList.remove(this);
}
protected void onOpen(WsOutbound outbound){
super.onOpen(outbound);
socketList.add(this);
}
@Override
protected void onBinaryMessage(ByteBuffer message) throws IOException {
}
@Override
protected void onTextMessage(CharBuffer message) throws IOException {
for(MessageInbound messageInbound : socketList){
CharBuffer buffer = CharBuffer.wrap(message);
WsOutbound outbound = messageInbound.getWsOutbound();
outbound.writeTextMessage(buffer);
outbound.flush();
}
}
}
}複製代碼
這個Servlet必需要繼承WebSocketServlet,接着建立一個繼承MessageInbound的WebSocketMessageInbound類,在該類中填充onClose、onOpen、onBinaryMessage和onTextMessage等方法便可完成各個事件的邏輯,其中onOpen會在一個WebSocket鏈接創建時被調用,onClose會在一個WebSocket關閉時被調用,onBinaryMessage則是Binary方式下接收到客戶端數據時被調用,onTextMessage則是Text方式下接收到客戶端數據時被調用。上面一段代碼實現了一個廣播的效果。架構
按照上面的處理邏輯,Tomcat對WebSocket的集成就不會太難了,就是在處理請求時若是遇到WebSocket協議請求則作特殊處理,保持住鏈接並在適當的時機調用WebSocketServlet的MessageInbound的onClose、onOpen、onBinaryMessage和onTextMessage等方法。因爲WebSocket通常建議在NIO模式下使用,因此看看NIO模式集成WebSocket協議。socket
如圖,對於WebSocket的客戶端鏈接被接收器接收後註冊到NioChannel隊列中,Poller組件不斷輪休是否有NioChannel須要處理,若是有則通過處理管道後進到繼承了WebSocketServlet的Servlet上,WebSocketServlet的doGet方法會處理WebSocket握手,告訴返回客戶端贊成升級協議。日後Poller繼續不斷輪休相關NioChannel,一旦發現是使用WebSocket協議的管道則會調用MessageInbound的相關方法,完成不一樣事件的處理,從而實現對WebSocket協議的支持。ide
歡迎關注:
ui