Tomcat如何實現WebSocket

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

相關文章
相關標籤/搜索