Reverse Ajax, Part 1: websocket

Source: Internet
Author: User

This article series discusses how to use reverse Ajax (reverse Ajax) technology to develop event-driven Web applications. Part 1 describes several different methods for implementing reverse Ajax communication: polling, piggyback, and comet with long-polling and streaming. In this article, we will learn a new technology for implementing reverse Ajax: Using websocket, a new HTML5 API. Websocket can be implemented locally by browser vendors, or by entrusting the call to a hidden flash component called Flash socket. This article also discusses some server-side constraints brought about by Reverse Ajax technology.

Preface

Today, users expect fast and dynamic applications that can be accessed through the web. This article series shows how to use reverse Ajax (reverse Ajax) technology to develop event-driven Web applications. Part 1 of this series describes reverse Ajax, polling, streaming, Comet, and long polling ). You have learned how comet uses HTTP long polling. This is the best way to reliably implement reverse Ajax, because all existing browsers provide support.

In this article, we will learn how to use websocket to implement reverse Ajax. Code examples are used to help describe websocket, flashsocket, server constraints, request-scoped services, and suspend long-lived requests. You can download the source code used in this article.

Prerequisites

Ideally, If You Want To fully understand this article, you should have a certain understanding of javascrpit and Java. The example created in this article is built using Google guice, a dependency injection framework written in Java. To read the content mentioned in this article, you should be familiar with the concept of dependency injection frameworks such as guice, spring, and Pico.

To run the example in this article, you also need the latest version of Maven and JDK (see references ).

Websocket

Websocket in HTML5 is a new reverse Ajax technology than comet. websocket enables two-way full-duplex communication channels, many browsers (Firefox, Google Chrome, and Safari) all have been supported. The connection is opened through an HTTP request called websocket handshake, which uses some special headers. The connection remains active. You can use JavaScript to write and receive data, just like using an original TCP interface.

The starting input of a websocket URL is WS: // or WSS: // (on SSL ).

The timeline in Figure 1 illustrates the communication using websocket. An HTTP handshake with a specific header is sent to the server, and then a socket can be used on the server or client through JavaScript, this interface can be used to asynchronously receive data through the event handle.

Figure 1. Reverse Ajax using websocket

The source code that can be downloaded in this article contains a websocket example. When running this example, you should see the output similar to listing 1. It illustrates how client events occur and how they are immediately displayed on the client. When the client sends some data, the server responds to the client's sending behavior.

Listing 1. websocket example in Javascript

[Client] websocket connection opened
[Server] 1 events
[Event] clientid = 0
[Server] 1 events
[Event] At Fri Jun 1721: 12: 01 EDT 2011
[Server] 1 events
[Event] from 0: qqq
[Server] 1 events
[Event] At Fri Jun 1721: 12: 05 EDT 2011
[Server] 1 events
[Event] from 0: VV

Generally, in Javascript, you will use websocket as described in Listing 2, if your browser supports it.

Listing 2. Javascript client example

VaR Ws = new websocket ('ws: // 127.0.0.1: 8080/async ');
WS. onopen = function (){
// Called when the connection is opened
};
WS. onerror = function (e ){
// Called when an error occurs, for example, when the connection is disconnected
};
WS. onclose = function (){
// Called when the connection is closed
};
WS. onmessage = function (MSG ){
// Called when the server sends a message to the client
// MSG. Data contains the message
};
// How to send some data to the server
WS. Send ('some data ');
// Close the set Interface
WS. Close ();

The data sent and received can be of any type, and websocket can be considered as a TCP interface. Therefore, it depends on the client and server that know the type of data to be sent back and forth. The example here sends a JSON string.

After the Javascript websocket object is created, if you carefully check the HTTP request in the browser Console (or firebug), you should see the unique header of websocket. Listing 3 provides an example.

Listing 3. Examples of HTTP requests and corresponding Headers

Request URL: WS: // 127.0.0.1: 8080/async
Request Method: Get
Status Code: 101 websocket protocol handshakerequest Headers
Connection: Upgrade
HOST: 127.0.0.1: 8080
Origin: http: // localhost: 8080
Sec-WebSocket-Key1: 1 & 1 ~ 33188yd] r8dp w75q
Sec-WebSocket-Key2: 17; 229*043 M 8
Upgrade: websocket
(Key3): B4: BB: 20: 37: 45: 3f: BC: C7

Response Headers
Connection: Upgrade
Sec-websocket-location: WS: // 127.0.0.1: 8080/async
Sec-websocket-origin: http: // localhost: 8080
Upgrade: websocket
(Challenge Response): AC: 23: A5: 7e: 5D: E5: 04: 6a: B5: F8: CC: E7: AB: 6d: 1A: 39

Websocket handshake uses all these headers to verify and set a persistent connection. The websocket JavaScript Object also contains two useful attributes:

WS. url: return the URL of the websocket server.
WS. readystate: returns the value of the current connection status.
1. Connecting = 0
2. Open = 1
3. Closed = 2

The processing of websocket on the server is a little more complicated. Currently, no Java specification supports websocket in a standard way. To use the websocket function of a Web Container (such as Tomcat or jetty), you must closely integrate the application code with a specific library of the container to access the websocket function.

The example in the websocket folder of the sample code uses jetty's websocket API, because we use the jetty container. Listing 4 shows the websocket processing program. (Part 1 of this series uses different backend websocket APIs .)

Listing 4. websocket handler of jetty container

Public final class reverseajaxservlet extends websocketservlet {
@ Override
Protected websocket dowebsocketconnect (httpservletrequest request, string protocol ){
Return [...]
}
}

For jetty, there are several ways to handle websocket handshakes. One of the easier ways is to subclass jetty's websocketservlet and implement the dowebsocketconnect method. This method requires you to return an instance of jetty's websocket interface. You must implement this interface and return an endpoint representing the websocket connection ). Listing 5 provides an example.

Listing 5. websocket implementation example

Class endpoint implements websocket {
Outbound outbound;
@ Override
Publicvoid onconnect (outbound ){
This. Outbound = outbound;
}
@ Override
Publicvoid onmessage (byte opcode, string data ){
// Called when a message is received
// You usually use this method.
}
@ Override
Publicvoid onfragment (Boolean more, byte opcode, byte [] data, int offset, int length ){
// Onmessage is called when a piece of content is completed
// Usually not write in this method
}
@ Override
Publicvoid onmessage (byte opcode, byte [] data, int offset, int length ){
Onmessage (opcode, new string (data, offset, length ));
}
@ Override
Publicvoid ondisconnect (){
Outbound = NULL;
}
}

To send a message to the client, you need to write the message to outbound, as shown in Listing 6:

Listing 6. Send a message to the client

If (outbound! = NULL & Outbound. isopen ()){
Outbound. sendmessage ('Hello world! ');
}

To disconnect and close the websocket connection to the client, use outbound. Disconnect ().

Websocket is a very powerful way to achieve two-way communication without latency. Firefox, Google Chrome, opera, and other modern browsers support this approach. According to the jwebsocket Website:

1. Chrome versions 4.0.249 and later contain localized websockets.
2. Safari 5.x contains a localized websocket.
3. Firefox 3.7a6 and 4.0b1 + contain localized websockets.
4. Opera includes a localized websocket from 10.7.9.67.

For more information about jwebsocket, see references.

Advantages

Websocket is powerful, bidirectional, low-latency, and easy to handle errors. It does not have as many connections as comet long polling and does not have any disadvantages of comet stream. Its APIs are also easy to use and can be directly used without additional layers, however, comet requires a good library to handle reconnection, timeout, Ajax requests, confirmation, and selection of different transmissions (Ajax long polling and jsonp polling ).

Disadvantages

Websocket has the following Disadvantages:

1. It is a new HTML5 standard that has not yet been supported by all browsers.

2. There is no request scope, because websocket is a TCP set of interfaces instead of an HTTP request. It is not easy to use with a range of request services, such as sessioninviewfilter of hibernate. Hibernate is a persistent framework that provides a filter on the periphery of the HTTP request. At the beginning of the request, a context (including transactions and JDBC connections) boundary is set in the request thread; at the end of the request, the filter destroys the context.

Flashsocket

For browsers that do not support websocket, some libraries can be rolled back to flash socket (through the flash interface. These libraries usually provide the same official websocket API, but they are implemented by entrusting the call to a hidden flash component included in the website.

Advantages

Flash socket transparently provides the websocket function, even in browsers that do not support HTML5 websocket.

Disadvantages

Flash socket has the following Disadvantages:

1. Install the flash plug-in. Generally, all browsers will have the plug-in ).

2. the firewall must open port 843 so that the flash component can send an HTTP request to retrieve the policy file containing domain authorization. If Port 843 cannot be reached, the database should have a rollback action or give an error. All these operations take some time (up to 3 seconds, depending on the database ), this reduces the speed of the website.

3. If the client is behind a proxy server, the connection to port 843 may be rejected.

The websocketjs project provides a bridging method, which requires a flash of at least 10 to provide websocket support for Firefox 3, Inernet Explorer 8, and Internet Explorer 9.

Suggestions

Compared with Comet, websocket brings more benefits. In daily development, the websocket supported by the client is faster and generates fewer requests (thus consuming less bandwidth ). However, since not all browsers support websocket, the best choice for the reverse Ajax library is to detect websocket support, and if websocket is not supported, it can also be rolled back to comet (long polling.

Since these two technologies need to obtain the best practices from all browsers and maintain compatibility, I suggest using a client's JavaScript library, the Library provides an abstraction layer on top of these technologies. Parts 3rd and 4th of this series will discuss some libraries, and part 5th will explain their applications. On the server side, as discussed in the next section, things will be slightly more complicated.

Reverse Ajax constraints on the server

Now you have an overview of the reverse Ajax solution available on the client. Let's take a look at the reverse Ajax solution on the server. So far, the examples are mainly client JavaScript code. On the server side, to accept reverse Ajax connections, some technologies require specific functions to process long-lived connections compared to the short HTTP requests you are familiar. To achieve better scalability, a new thread model should be used, which requires a specific API in Java to suspend the request. Also, for websocket, you must correctly manage the service scopes used in the application.

Thread and non-blocking I/O

Generally, the web server associates a thread or process with each incoming HTTP connection. This connection can be persistent (active), so that multiple requests can be connected through the same connection. In this example, the Apache web server can be configured to mpm_fork or mpm_worker mode to change this line. Java Web servers (including application servers-this is the same thing) usually use a separate thread for each incoming connection.

The generation of A New thread will lead to memory consumption and resource waste, because it does not guarantee that the generated thread will be used. The connection may be established, but no data from the client or server is being sent. Whether or not this thread is used, it will consume the memory and CPU resources used for scheduling and context switching. In addition, when configuring the server in thread mode, you usually need to configure a thread pool (set the maximum number of threads that process incoming connections ). If the value is not properly configured and the value is too small, you will eventually encounter thread hunger; requests will remain in the waiting state until there are threads available to process them, when the maximum number of concurrent connections is reached, the response time decreases. On the other hand, configuring a high value can cause an exception of insufficient memory. If multiple threads are generated, all available JVMs are consumed, resulting in server crash.

Java recently introduced a new I/o api called non-blocking I/O. This API uses a selector to avoid binding a thread every time a new HTTP connection is established on the server. When data arrives, an event is received, then a thread is allocated to process the request. Therefore, this approach is called a thread-per-request mode for each request. It allows web servers, such as WebSphere and jetty, to use a fixed number of threads to accommodate and process more and more user connections. In the case of the same hardware configuration, the scalability of the Web server running in this mode is much better than that running in each thread-per-connection model.

In the blog of Philip McCarthy (author of comet and reverse Ajax), there is an interesting benchmark for measuring the scalability of these two thread modes (see the link in references ). In Figure 2, you will find the same mode: when there are too many connections, the thread mode will stop working.

Figure 2. benchmark for measuring the thread mode

Every thread connection mode (threads in figure 2) usually has a better response time, because all threads are started, ready, and waiting, however, when the number of connections is too high, it will stop providing services. In the thread mode of each request (continuations in figure 2), the thread is used to provide services for the arriving request, and the connection is processed by a NiO selector. The response time may be slower, but the thread will be recycled. Therefore, this solution has better scalability in large-capacity connections.

To understand how a thread works behind the scenes, you can think of a Lego block as a selector. Each time the incoming connection reaches this Lego block, it is identified by a pin. The Lego block/selector has the same number of pins (as many keys) as the number of connections ). Then, you only need a thread to wait for the occurrence of new events, and then traverse these pins. When something happens, the selector thread retrieves the key value from the event and then can use a thread to provide services for the incoming request.

The "Rox Java NiO tutorial" tutorial provides a good example of using NiO in Java (see references ).

Services with request scopes

Many frameworks provide services or filters to process Web requests that reach the servlet. For example, a filter will:

1. Bind The JDBC connection to a request thread, so that the entire request uses only one connection.

2. Submit the changes at the end of the request.

Another example is the guice servlet extension of Google guice (a dependency injection library. Similar to spring, guice can bind services to the request scope. An instance can only be created once for each new request (see references for more information ).

The common practice includes using the user ID to cache the user objects retrieved from the repository in the request, and the user ID is taken from the clustered http session. In Google guice, you may have code similar to the code given in listing 7.

Listing 7. Binding Request scopes

@ Provides
@ Requestscoped
Member member (authmanager,
Memberrepository ){
Return memberrepository. findbyid (authmanager. getcurrentuserid ());
}

When a member is injected into the class, guice tries to obtain the object from the request. If it does not find the object, it executes the repository call and puts the result in the request.

The request scope can be used together with any reverse Ajax solution other than websocket, and any other solution that relies on HTTP requests, whether short or long, each request can be executed through the servlet distribution system. When you complete a paused (long-lived) HTTP request, you will learn in this series of successor sections that there is another way to let the request pass the filter chain again.

For websocket, data is directly sent to the onmessage callback function, as is the case in the TCP interface. There is no HTTP request to deliver this data, so there is no request context to get or store the scope object. Therefore, the service that requires the scope object will fail to be used in the onmessage callback. The example of guice-and-websocket In the downloadable source code shows how to bypass this restriction so that the request scope object can still be used in the onmessage callback. When you run this example and click each button on the webpage to test an Ajax call (with request scope), A websocket call, and a websocket call using a simulated request scope, you will get the output shown in figure 3.

Figure 3. websocket handler using the request scope Service

You may encounter these problems when using any of the following technologies:

1. Spring

2. hibernate

3. Any other framework that requires the request scope or each request model, such as opensessioninviewfilter.

4. Any system that uses threadlocal within the filter to specify the scope of variables as the request thread and access these variables later.

Guice has an elegant solution, as shown in listing 8:

Listing 8. Simulating a request scope in the onmessage callback of websocket

// When dowebsocketmethod is called
// Save to request reference
Httpservletrequest request = [...]
Map, Object> bindings = new hashmap, Object> ();
// I have a service that requires a request to obtain the session
// Therefore, I provide a request, but you can provide any other
// Possible binding required
Bindings. Put (key. Get (httpservletrequest. Class), request );
Servletscopes. scoperequest (New callable (){
@ Override
Public object call () throws exception {
// Call Your repository or any service that uses the scope object
Outbound. sendmessage ([...]);
Return NULL;
}
}, Bindings). Call ();

Suspend long-lived requests

If you use Comet, there is another obstacle, that is, how does the server pause a long-lived request without affecting performance, then, when server events arrive, restore and complete the request as quickly as possible?

Obviously, you cannot simply stop requests and responses there, which will cause thread hunger and high memory consumption. Pause a long-lived request in non-blocking I/O. in Java, this requires a Unique API. The servlet 3.0 specification provides such an API (see part 1 of this series ). Listing 9 provides an example.

Listing 9. using Servlet 3.0 to define an asynchronous Servlet

<? XML version = "1.0" encoding = "UTF-8"?> <Web-app version = "3.0" xmlns = "http://java.sun.com/xml/ns/javaee"
Xmlns: J2EE = "http://java.sun.com/xml/ns/javaee"
Xmlns: xsi = "http://www.w3.org/2001/xmlschema-instance"
Xsi: schemalocation = "http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml
/Ns/J2EE/web-app_3.0.xsd ">

<Servlet>
<Servlet-Name> events </servlet-Name>
<Servlet-class> reverseajaxservlet </servlet-class>
<Async-supported> true </async-supported>
</Servlet>

<Servlet-mapping>
<Servlet-Name> events </servlet-Name>
<URL-pattern>/ajax </url-pattern>
</Servlet-mapping>

</Web-app>

After defining an asynchronous servlet, you can use the servlet 3.0 API to suspend and restore a request, as shown in listing 10:

Listing 10. Suspending and resuming a request

Asynccontext = Req. startasync ();
// Save the reference of asynccontext somewhere // you can restore and complete it in another thread as needed
Httpservletresponse Req =
(Httpservletresponse) asynccontext. getresponse ();
Req. getwriter (). Write ("data ");
Req. setcontenttype ([...]);
Asynccontext. Complete ();

Before servlet 3.0, each container had its own mechanism. The continuation of Jetty is a famous example. Many reverse Ajax libraries in Java depend on the continuation of jetty. It is not an amazing practice, and you do not need to run your application on the jetty container. This API is smart because it can detect the container you are running. If it is running on another container, such as Tomcat or Grizzly, if the servlet 3.0 API is available, it will be rolled back to the servlet 3.0 API. This is no problem for Comet, but if you want to take advantage of websocket, you have no choice but to use container-specific functions.

The servlet 3.0 specification has not yet been released, but many containers have already implemented this API, because it is also a standard practice for implementing reverse Ajax.

Conclusion

Although websocket has some shortcomings, it is a powerful reverse Ajax solution. It is not yet implemented in all browsers, and it is not easy to use on the Java Server Side if there is no reverse Ajax library help. Because you are not using a standard request-response style, you cannot rely on the scope of the filter chain for execution. Comet and websocket require specific container functions on the server. Therefore, when using a new container, You need to note that it may not be extended.

Please keep an eye on Part 1 of this series. This part will explore different server-side APIs for Comet and websocket. You can also understand Atomsphere, which is a reverse Ajax framework.

Download

Description name size Download Method

Source code reverse_ajaxpt2_source.zip 14kb HTTP

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.