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

相关文章
相关标签/搜索