Home > Article > Web Front-end > Web and WebSocket Practical Talk
Why is the real-time Web so important? We live in a real-time world, so the ultimate and most natural state of the Web should also be real-time. Users need real-time communication, data and search. Our requirements for real-time information on the Internet are also getting higher and higher. If information or messages are updated after a delay of several minutes, it is simply unbearable. Now many large companies (such as Google, Facebook and Twitter) have begun to pay attention to the real-time Web and provide real-time services. Real-time Web will be one of the hottest topics in the future.
The development history of the real-time Web
The traditional Web is based on the HTTP request/response model: the client requests a new page, and the server sends the content to the client , the client must resend the request when requesting another page. Later, someone proposed AJAX, which made the page experience more "dynamic" and could initiate requests to the server in the background. However, if the server has more data that needs to be pushed to the client, it is not possible to directly send the data from the server to the client after the page is loaded. Real-time data cannot be "pushed" to the client.
In order to solve this problem, many solutions have been proposed. The simplest (brute force) solution is to use polling: request new data from the server every once in a while. This makes the application feel real-time to the user. In fact, this will cause latency and performance problems, because the server has to handle a large number of connection requests every second, and each request will have a TCP three-way handshake and HTTP header information. Although polling is still used in many applications today, it is not the most ideal solution.
Later, with the introduction of Comet technology, many more advanced solutions appeared. These technical solutions include permanent frame (forever frame), XHR stream (xhr-multipart), htmlfile, and long polling. Long polling means that the client initiates an XHR connection to the server. This connection is never closed, and the connection is always suspended for the client. When the server has new data, it will promptly send a response to the client, and then close the connection. Then the entire process is repeated, and in this way a "server push" is achieved.
Comet technology is a non-standard hack technology. Because of this, browser compatibility becomes a problem. First of all, the performance problem cannot be solved. Every connection initiated to the server carries complete HTTP header information, which will be a thorny problem if your application requires very low latency. Of course, it’s not that there is anything wrong with Comet itself, because Comet is our only choice until there are other alternatives.
Browser plug-ins (such as Flash) and Java are also used to implement server push. They can establish socket connections directly with the server based on TCP, which is very suitable for pushing real-time data to the client. The problem is that not all browsers have these plug-ins installed, and they are often blocked by firewalls, especially on corporate networks.
Now the HTML5 specification has prepared an alternative for us. However, this specification is a bit ahead of its time, and many browsers do not yet support it, especially IE. It is of little help to many current developers. Since most browsers have not yet implemented HTML5 WebSocket, the current best way is still to use Comet.
WebSocket Past and Present Life
As we all know, the interaction process of Web applications is usually that the client sends a request through the browser, the server receives the request, processes it and returns the result to the client, and the client browses The information is presented by the server. This mechanism is acceptable for applications where information changes are not particularly frequent, but it is insufficient for applications with high real-time requirements and massive concurrency. Especially under the current booming development trend of mobile Internet in the industry, high concurrency is closely related to users. Real-time response is a problem that Web applications often face, such as real-time information on financial securities, geographical location acquisition in Web navigation applications, real-time message push on social networks, etc.
Traditional request-response model Web development usually uses real-time communication solutions when dealing with such business scenarios. The most common ones are:
Polling. The principle is simple and easy to understand, that is, the client Keep the data synchronization between the client and the server by sending requests to the server in the form of frequent requests at certain intervals. The problem is obvious. When the client sends requests to the server at a fixed frequency, the data on the server may not be updated, resulting in many unnecessary requests, a waste of bandwidth, and low efficiency.
Based on Flash, AdobeFlash completes data exchange through its own Socket implementation, and then uses Flash to expose the corresponding interface for JavaScript calls to achieve real-time transmission. This method is more efficient than polling, and because Flash has a high installation rate, it has a wide range of application scenarios. However, Flash support on mobile Internet terminals is not good. There is no Flash in the IOS system. Although there is Flash support in Android, the actual use effect is not satisfactory, and the hardware configuration requirements of the mobile device are relatively high. In 2012, Adobe officially announced that it would no longer support the Android 4.1+ system, announcing the death of Flash on mobile terminals.
As can be seen from the above, the traditional Web model will encounter insurmountable bottlenecks when dealing with high concurrency and real-time requirements. We need an efficient and energy-saving two-way communication mechanism to ensure real-time data transmission. In this context, WebSocket, known as Web TCP, came into being based on the HTML5 specification.
In the early days, HTML5 did not form a unified specification in the industry. Various browsers and application server manufacturers had different similar implementations, such as IBM's MQTT, Comet open source framework, etc. Until 2014, HTML5 was adopted by IBM, Microsoft, With the promotion and cooperation of giants such as Google, the dust finally fell into place, and it was officially implemented from a draft into an actual standard specification. Various application server and browser manufacturers gradually began to unify. The WebSocket protocol was also implemented in JavaEE7, so that both the client and the server can use WebSocket. All are complete, readers can check the HTML5 specification and become familiar with the new HTML protocol specification and WebSocket support.
WebSocket mechanism
The following is a brief introduction to the principle and operating mechanism of WebSocket.
WebSocket is a new protocol in HTML5. It realizes full-duplex communication between the browser and the server, which can better save server resources and bandwidth and achieve real-time communication. It is built on TCP and transmits data through TCP like HTTP. However, its biggest difference from HTTP is:
WebSocket is a two-way communication protocol. After establishing a connection, the WebSocket server and Browser/Client Agent can actively send or receive data to each other, just like Socket;
WebSocket requires Similar to TCP, the client and server are connected through a handshake, and they can communicate with each other only after the connection is successful.
The interaction between traditional HTTP client and server in non-WebSocket mode is shown in the following figure:
Figure 1. Traditional HTTP request response client-server interaction diagram
The interaction between client and server using WebSocket mode is as shown below:
Figure 2. WebSocket request response client-server interaction diagram
Figure It can be seen from the comparison that compared to the traditional HTTP mode in which each request-response requires the client to establish a connection with the server, WebSocket is a TCP long-connection communication mode similar to Socket. Once the WebSocket connection is established, subsequent data is in frame sequence. form of transmission. Before the client disconnects the WebSocket connection or the server disconnects, there is no need for the client and server to reinitiate the connection request. In the case of massive concurrency and heavy interactive load traffic between the client and the server, it greatly saves the consumption of network bandwidth resources and has obvious performance advantages. Moreover, the client sends and receives messages on the same persistent connection, in real time. The sexual advantage is obvious.
Let’s take a look at the difference between WebSocket communication and traditional HTTP through the interactive messages between the client and the server:
On the client, new WebSocket instantiates a new WebSocket client object. Connect to the server WebSocket URL similar to ws://yourdomain:port/path. The WebSocket client object will automatically parse and identify it as a WebSocket request, thereby connecting to the server port and performing the handshake process between the two parties. The format of the data sent by the client is similar:
List 1.WebSocket client connection message
GET /webfin/websocket/ HTTP/1.1 Host: localhost Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg== Origin: http://localhost:8080 Sec-WebSocket-Version: 13
It can be seen that the WebSocket connection message initiated by the client is similar to the traditional HTTP message. The "Upgrade: websocket" parameter value indicates that this is a WebSocket type request. "Sec-WebSocket-Key" is one sent by the WebSocket client. The base64-encoded ciphertext requires the server to return a corresponding encrypted "Sec-WebSocket-Accept" response, otherwise the client will throw an "Error during WebSocket handshake" error and close the connection.
The data format returned by the server after receiving the message is similar:
Listing 2.WebSocket server response message
HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
The value of "Sec-WebSocket-Accept" It is calculated by the server using the same key as the client and returned to the client. "HTTP/1.1 101 Switching Protocols" means that the server accepts the client connection of the WebSocket protocol. After such request-response processing, the client server The WebSocket connection handshake is successful, and subsequent TCP communication can be carried out. Readers can refer to the WebSocket protocol stack to learn more detailed interactive data formats between the WebSocket client and server.
In terms of development, the WebSocket API is also very simple. We only need to instantiate WebSocket and create a connection. Then the server and the client can send and respond to each other's messages. In the WebSocket implementation and case analysis section below, you can See detailed WebSocket API and code implementation.
WebSocket Implementation
As mentioned above, the implementation of WebSocket is divided into two parts: the client and the server. The client (usually a browser) issues a WebSocket connection request, and the server responds. Implementation An action similar to TCP handshake, thus forming a long HTTP long connection fast channel between the browser client and the WebSocket server. Subsequent direct data transmission between the two eliminates the need to initiate a connection and respond.
The following is a brief description of the WebSocket server API and client API.
WebSocket server API
The WebSocket server has basically been supported by APIs that comply with the JEE JSR356 standard specification in various mainstream application server manufacturers (see JSR356 WebSocket API specification for details), some of which are listed below Common commercial and open source application servers support WebSocket Server:
Table 1. WebSocket server support
##ManufacturerRemarks
##IBM WebSphere WebSphere 8.0 or above is supported, and versions prior to 7.X combined with MQTT support similar HTTP long connections Oracle WebLogic WebLogic 12c is supported, 11g and 10g versions support similar HTTP persistent connections through HTTP Publish Microsoft IIS IIS 7.0+ support Apache Tomcat Tomcat 7.0.5+ support, 7.0.2X and 7.0.3X through custom API Support Jetty Jetty 7.0 + Support Below we use the service side example code of Tomcat7.0.5 to explain the implementation of the WebSocket server: JSR356. .* API, you can use the @ServerEndpoint annotation as an ordinary Java object (POJO) as the endpoint of the WebSocket server. The code example is as follows: Listing 3. WebSocket server API example@ServerEndpoint("/echo") public class EchoEndpoint { @OnOpen public void onOpen(Session session) throws IOException { //以下代码省略... } @OnMessage public String onMessage(String message) { //以下代码省略... } @Message(maxMessageSize=6) public void receiveMessage(String s) { //以下代码省略... } @OnError public void onError(Throwable t) { //以下代码省略... } @OnClose public void onClose(Session session, CloseReason reason) { //以下代码省略... } }Code Explanation: The concise code above establishes a WebSocket server. The annotation annotation endpoint of @ServerEndpoint("/echo") indicates that the WebSocket server is run at ws://[Server IP or Domain name]:[Server port]/websockets/echo access endpoint, the client browser can already initiate HTTP persistent connections to the WebSocket client API. The class annotated with ServerEndpoint must have a public parameterless constructor. The @onMessage annotated Java method is used to receive incoming WebSocket information. This information can be in text format or binary format.
OnOpen 在这个端点一个新的连接建立时被调用。参数提供了连接的另一端的更多细节。Session 表明两个 WebSocket 端点对话连接的另一端,可以理解为类似 HTTPSession 的概念。
OnClose 在连接被终止时调用。参数 closeReason 可封装更多细节,如为什么一个 WebSocket 连接关闭。
更高级的定制如 @Message 注释,MaxMessageSize 属性可以被用来定义消息字节最大限制,在示例程序中,如果超过 6 个字节的信息被接收,就报告错误和连接关闭。
注意:早期不同应用服务器支持的 WebSocket 方式不尽相同,即使同一厂商,不同版本也有细微差别,如 Tomcat 服务器 7.0.5 以上的版本都是标准 JSR356 规范实现,而 7.0.2x/7.0.3X 的版本使用自定义 API (WebSocketServlet 和 StreamInbound, 前者是一个容器,用来初始化 WebSocket 环境;后者是用来具体处理 WebSocket 请求和响应,详见案例分析部分),且 Tomcat7.0.3x 与 7.0.2x 的 createWebSocketInbound 方法的定义不同,增加了一个 HttpServletRequest 参数,使得可以从 request 参数中获取更多 WebSocket 客户端的信息,如下代码所示:
清单 4.Tomcat7.0.3X 版本 WebSocket API
public class EchoServlet extends WebSocketServlet { @Override protected StreamInbound createWebSocketInbound(String subProtocol, HttpServletRequest request) { //以下代码省略.... return new MessageInbound() { //以下代码省略.... } protected void onBinaryMessage(ByteBuffer buffer) throws IOException { //以下代码省略... } protected void onTextMessage(CharBuffer buffer) throws IOException { getWsOutbound().writeTextMessage(buffer); //以下代码省略... } }; } }
因此选择 WebSocket 的 Server 端重点需要选择其版本,通常情况下,更新的版本对 WebSocket 的支持是标准 JSR 规范 API,但也要考虑开发易用性及老版本程序移植性等方面的问题,如下文所述的客户案例,就是因为客户要求统一应用服务器版本所以使用的 Tomcat 7.0.3X 版本的 WebSocketServlet 实现,而不是 JSR356 的 @ServerEndpoint 注释端点。
WebSocket 客户端 API
对于 WebSocket 客户端,主流的浏览器(包括 PC 和移动终端)现已都支持标准的 HTML5 的 WebSocket API,这意味着客户端的 WebSocket JavaScirpt 脚本具备良好的一致性和跨平台特性,以下列举了常见的浏览器厂商对 WebSocket 的支持情况:
表 2.WebSocket 客户端支持
浏览器 支持情况
Chrome Chrome version 4+支持
Firefox Firefox version 5+支持
IE IE version 10+支持
Safari IOS 5+支持
Android Brower Android 4.5+支持
客户端 WebSocket API 基本上已经在各个主流浏览器厂商中实现了统一,因此使用标准 HTML5 定义的 WebSocket 客户端的 JavaScript API 即可,当然也可以使用业界满足 WebSocket 标准规范的开源框架,如 Socket.io。
以下以一段代码示例说明 WebSocket 的客户端实现:
清单 5.WebSocket 客户端 API 示例
var ws = new WebSocket(“ws://echo.websocket.org”); ws.onopen = function(){ws.send(“Test!”); }; ws.onmessage = function(evt){console.log(evt.data);ws.close();}; ws.onclose = function(evt){console.log(“WebSocketClosed!”);}; ws.onerror = function(evt){console.log(“WebSocketError!”);};
第一行代码是在申请一个 WebSocket 对象,参数是需要连接的服务器端的地址,同 HTTP 协议开头一样,WebSocket 协议的 URL 使用 ws://开头,另外安全的 WebSocket 协议使用 wss://开头。
第二行到第五行为 WebSocket 对象注册消息的处理函数,WebSocket 对象一共支持四个消息 onopen, onmessage, onclose 和 onerror,有了这 4 个事件,我们就可以很容易很轻松的驾驭 WebSocket。
When the Browser and WebSocketServer are successfully connected, the onopen message will be triggered; if the connection fails, sending and receiving data fails, or there is an error in processing the data, the browser will trigger the onerror message; when the Browser receives the data sent by the WebSocketServer, it will Trigger the onmessage message, the parameter evt contains the data transmitted by the Server; when the Browser receives the connection closing request sent by the WebSocketServer, the onclose message will be triggered. We can see that all operations are triggered using asynchronous callbacks, which will not block the UI, achieve faster response time, and provide a better user experience.