Search |
||
Turn a HTTP connection into a full-duplex communication (part one)Posted by rexyoung on September 10, 2008 at 4:12 PM PDT
Problem
This trick is for a specific situation where two applications (both in your hands) want efficient and convenient communication, and HTTP connection is the only method available between them. HTTP protocol is well-known as a request-and-response standard over internet. One end sends a HTTP request, and waits the other end to reply a HTTP response. The essentials of half-duplex and one-time use per connection make it inefficient and inconvenient for the above situation. Some previous efforts may be found to ease it a little bit. For example, a reusable HTTP connection that allows multiple pairs of request-and-response, a server (e.g. servlet) push technique that improves efficiency beyond one request one response model, or a heavy method like Web Service. Goal What I am looking for is a full-duplex communication as simple as a socket connection.
When I put these features into code, it will look like the following.
interface Port {
InputStream getInputStream() throws IOException;
OutputStream getOutputStream() throws IOException;
void close() throws IOException;
}
The construction of a port instance varies depends on which side of HTTP connection it is and what http toolbox it uses.The side that issues an outgoing HTTP connection may use HttpURLConnection (a JDK class,) HttpClient/HttpCore (an Apache project,) or homemade code. Talk about homemade code, it does not necessarily need to implement the complete HTTP specification (RFC 2616). It just need codes to issue a HTTP POST request with several hard coded headers. It is usually good enough if it can handle SSL, HTTP authentication, and proxy. Meanwhile, another side that accepts an incoming HTTP connection may reside in a servlet container, or on its own using homemade code. In my case, I implemented a client side that uses HttpClient and a server side that is running in a Tomcat. I will post the source code in a late part, say part two. Task 1: Push HTTP to its limit First, we pick HTTP POST method. According to RFC 2616, both the request and response of a POST method may have a message body which will carry the content during communication. Second, we pick Chunked as the Transfer Coding. RFC 2616 defines two ways to describes the size of a message body. One is to specify its size per request. This means you can not send bytes more than as the HTTP header Content-Length says. The other way is to use a Chunked transfer coding. Each chunk contains its own size indicator and data. A zero-sized chunk acts as the last one to complete the message body. Thus we are able to send unlimited amount of bytes, and close the message body when we are done. A POST method with message body using Chunked transfer coding works this way:
Since step 3, the communication enters full-duplex mode. Your application has control how much data to send and when to stop. On a big picture, all full-duplex communication are encapsulated within a single request-and-response. The task tells us it is possible to turn a HTTP connection into a full-duplex communication. But how to make it work with its context like with HttpClient or in a Servlet is another story. Task 2: Work with HttpClient The typical usage of HttpClient looks like the following. It sends the entire request and then retrieve response. This does not leave room for us to use both input and output at the same time. We must customize HttpClient for our goal.
HttpClient client = new HttpClient();
PostMethod method = new PostMethod(url);
int returnCode = client.executeMethod(method);
First, we need tell HttpClient to use Chunked coding. Second, HttpClient has its own ChunkedOutputStream class that wouldn't work for us. Because it uses an internal buffer, and hold everything until buffer is full. And there is no way to flush out anything in the buffer before the buffer is full except closing it. So we need our own ChunkedOutputStream. Third, we want the output stream is still alive when a return code is retrieved. Otherwise we would not have both live intput and output streams.The good news is that all of above are doable. I have already completed my implementation and it is working. I will show you late. Task 3: Work with Servlet Servlet specification requires all servlet containers to handle Chunked coding for servlet instances. Inside any do method, HttpServletrequest.getInputStream() is transparent to Chunked coding. You do not need to do anything. But you need to tell servlet container if you want outgoing stream using Chunked coding. According to the specification, it can be done by adding a header like this “Transfer-Encoding=Chunked†to response. So working with servlet is easy. However, not all servlet containers comply with the specification on this matter. The good news is that Tomcat works. I am willing to provide some source code that work with HttpClient and Tomcat in part two. I need your feedback to see whether it is worth the effort. Because I can not directly post the source code I used at work. I have to rewrite it and make it generic. p.s. In theory, the method mentioned here should work with most today's systems as all it uses are defined by specifications. However, you should make sure the method will work with your target system before you invest into it. Here is the reasons. »
Related Topics >>
Programming Comments
Comments are listed in date ascending order (oldest first)
Submitted by lukman_jaji on Fri, 2008-09-12 07:39.
cant wait for this man. it would ake building chat systems for the net a piece of cake
Submitted by cowwoc on Fri, 2008-09-12 07:52.
I'm interested too. I look forward to a future post containing some sample code.
Submitted by jfarcand on Fri, 2008-09-12 09:33.
Interesting :-) I suspect any server that support Comet will works with your approach, e.g not only Tomcat, but also Grizzly/GlassFish/Jetty :-). A+
Submitted by rexyoung on Fri, 2008-09-12 09:51.
Thanks for the comments. I will work out a prototype (based on the working version at work) the weekend and post it by Monday.
Submitted by ference on Fri, 2008-09-12 23:42.
Rex,
by using the http library xLightweb.org you get full-duplex for free. See example:
HttpClient httpClient = new HttpClient();
FutureResponseHandler respHdl = new FutureResponseHandler();
BodyDataSink outBodyChannel = httpClient.send(new HttpRequestHeader("POST", url, respHdl);
outBodyChannel.flush();
IHttpResponse resp = respHdl.getResponse(); // wait for resp header
BlockingBodyDataSource inBodyChannel = resp.getBlockingBody();
InputStream is = Channels.newInputStream(inBodyChannel);
OutputStream os = Channels.newOutputStream(outBodyChannel);
...
cheers
ference
Submitted by aschiffman on Fri, 2008-09-12 11:29.
Rex my main man nice project;) There is an interesting communication paradigm in the BitTorrent P2P technology that allows a user to download multiple chunks of a file from different locations in segments piece by piece from different locations. Does (or do you have plans) to implement functionality support for similar types of protocols in JSASB?
http://en.wikipedia.org/wiki/BitTorrent_(protocol)
Take Care and Thanks for the good work!
Aaron
Submitted by jmelchio on Fri, 2008-09-12 17:20.
Sounds like a great idea. Looking forward to the next installment of the article.
Cheers, Joris.
Submitted by joconner on Thu, 2008-09-11 08:17.
I'm very interested in how you are using HTTP to replace a typical socket connection! I'm attempting something like this in my current job, and I'd very much like to see how you've done it.
Submitted by ilazarte on Sat, 2008-09-13 10:21.
looking forward to seeing the next installment as well!
Submitted by rexyoung on Sun, 2008-09-14 21:57.
Aaron, I think it will be easy to implement a file transfer protocol once you turn the HTTP into full-duplex model. Actually I was forced to solve this issue for a deployment server which sometimes only have HTTP connection available. Now I am able to resume and/or re-assemble random chunks when moving big files like HD movies.
Jsasb? I am not sure. Jsasb is about message-passing not communication. Maybe I couldn't get you right. I will contact you later.
Submitted by rexyoung on Sun, 2008-09-14 21:58.
ference, I took a look on the xLightweb.org. It seems a very powerful toolbox. Thanks for letting us know.
|
||
|
|