應用servlet實現http的長連接

爲了實現服務端向客戶端推送的模式,如果自己寫的socket到時順理成章的很容易實現。但是,甲方要我們用標準的http協議。當然,自己寫http服務器倒是也沒什麼題,我開始也時這麼想的,而且都設計好了分佈計算和負載平衡的方式。但有人暫時還建議我們用中間件,他們的意見就像天氣的臉,一會兒這樣,一會兒那樣。於是在這方面考慮,無奈和喜悅同時而生。無奈的是,直接應用中間件,成就感將大打折扣。喜悅的是,直接應用中間件,我的開發量幾乎可以說就是實現商業邏輯,分佈計算和負載平衡都可以配置中間件實現。

那麼如果用中間件寫http服務,來應付客戶端的請求並實現推送模式呢。在開會的時候, 一個同事使我猛醒。他說他就直接寫一個servlet,這就是標準的http服務。這時,我便想起了我曾寫過用java中URL累實現的http客戶端。不妨用之,這樣服務端客戶端就都有了試驗的依據。其中我問及同事是否實現長連接,結果他說沒有 (應該是沒想到這點),但是我們知道,服務推送的模式每次都打開和關閉與客戶端的連接必然很耗資源。而我們實現的系統就是具備長連接,而且很耗帶寬的連接,不管是長連接還是短連接。如果每次數據傳送都要建立連接,而且請求非常頻繁的假推送模式效能很低的話,我們就可以試一試長連接推送的方式。

也許你會想,servlet的長連接怎麼實現呢。不錯,用while循環就可以了。平常我們用瀏覽器瀏覽網頁,大都一次請求,然後得到結果,關閉連接。其實如果服務端用一個死循環,一直在發送數據,而且客戶端沒有關閉的話,連接是一直存在的。我們完全可以用這條連接實現服務推模式。當然,監聽的客戶端自己寫一個很簡單,如下:

package test;

import java.io.InputStream;
import java.net.URL;

public class LongConnectionClient {

public static void main(String args[]) {
try {

//確定服務地址
URL url = new URL("http://localhost:8080/HttpConnectionTest/LongConnectionTest");
InputStream in=url.openStream();
int n = -1;
byte[] b = new byte[1024];
//從服務端讀取數據並打印
while((n=in.read(b))!=-1)
{
String s=new String(b,0,n, "UTF-8");
System.out.println(s);
}

} catch (Exception e) {
e.printStackTrace();
}
}

}


服務端的代碼也異常簡單:

package test;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LongConnectionTest extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
static final long serialVersionUID = 1L;

public LongConnectionTest() {
super();
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

response.setCharacterEncoding("UTF-8");
response.setContentType("text/html");

PrintWriter pr = response.getWriter();

try {
while(true) {
pr.print("有時候你不得不相信");
//flush的作用很重要,當你任務寫給客戶端的數據總夠多的時候
//調用之,客戶端方能讀取到。
//否則,在數據長度達到上限或者連接關閉之前,客戶端讀不到數據
pr.flush();
Thread.sleep(500);
}
} catch(Exception e) {
e.printStackTrace();
}

}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章