Tomcat 服务器是一个免费的开放源代码的 web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试 JSP 程序的首选。
这篇文章主要介绍了 Tomcat 如何实现 WebSocket 的相关资料, 对 WebSocket 协议通信的过程进行了详细介绍,需要的朋友可以参考下
Tomcat 如何实现 WebSocket
WebSocket 协议属于 html5 标准,越来越多浏览器已经原生支持 WebSocket,它能让客户端和服务端实现双向通信。在客户端和服务器端建立一条 WebSocket 连接后,服务器端消息可直接发送到客户端,从而打破传统的请求响应模式,避免了无意义的请求。比如传统的方式可能会使用 AJAX 不断请求服务器端,而 WebSocket 则可以直接发送数据到客户端且客户端不必请求。同时,由于有了浏览器的原生支持,编写客户端应用程序也变得更加便捷且不必依赖第三方插件。另外,WebSocket 协议摒弃了 HTTP 协议繁琐的请求头,而是以数据帧的方式进行传输,效率更高。
图为 WebSocket 协议通信的过程,首先客户端会发送一个握手包告诉服务器端我想升级成 WebSocket,不知道你服务器端是否同意,这时如果服务器端支持 WebSocket 协议则会返回一个握手包告诉客户端没问题,升级已确认。然后就成功建立起了一条 WebSocket 连接,该连接支持双向通信,并且使用 WebSocket 协议的数据帧格式发送消息。
握手过程需要说明下,为了让 WebSocket 协议能和现有 HTTP 协议 Web 架构互相兼容,所以 WebSocket 协议的握手要基于 HTTP 协议,比如客户端会发送类似如下的 HTTP 报文到服务器端请求升级为 WebSocket 协议,其中包含的 Upgrade: websocket 就是告诉服务器端我想升级协议:
- 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 的简单例子:
- 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 协议。
如图,对于 WebSocket 的客户端连接被接收器接收后注册到 NioChannel 队列中,Poller 组件不断轮休是否有 NioChannel 需要处理,如果有则经过处理管道后进到继承了 WebSocketServlet 的 Servlet 上,WebSocketServlet 的 doGet 方法会处理 WebSocket 握手,告诉返回客户端同意升级协议。往后 Poller 继续不断轮休相关 NioChannel,一旦发现是使用 WebSocket 协议的管道则会调用 MessageInbound 的相关方法,完成不同事件的处理,从而实现对 WebSocket 协议的支持。
来源: http://www.phperz.com/article/17/1215/359277.html