小菜毛毛技術分享

          與大家共同成長

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            164 Posts :: 141 Stories :: 94 Comments :: 0 Trackbacks
          http://homelink.javaeye.com/blog/293328#comments
          參考文檔 http://www.ibm.com/developerworks/cn/web/wa-lo-comet/

                  comet是HTTP長連接,就是在HTTP發送請求時,服務器不立刻發送響應信息給客戶端, 而是保持著連接,等待一定情況發生后才把數據發送回去給客戶端。所以用comet可以實現服務器端的數據實時地發送給客戶端。

                  本文主要是用java和js來簡單地實現comet,最后附上源碼和使用例子。

                  在客戶端用XMLRequest發送請求到服務器,在服務器端用一個servlet來接收XMLRequest的請求,當接收到請 求時,并不立刻響應客戶端,而是把該servlet線程阻塞,等到一定事件發生后,再響應客戶端。當客戶端接收到服務端的響應后,調用自定義的回調函數來 處理服務器發送回來的數據,處理完成后,再發送一個XMLRequest請求到服務端,這樣循環下去,就可以實現數據的實時更新,又不必要在客戶端不斷地 輪循(polling)。

                   利用該comet的實現(以后簡稱為keeper)時,只要在客戶端注冊事件和寫一個處理返回數據的回調函數,然后在服務端實現 keeper中的EventListener接口,調用Controller.action(eventListener,eventType)就可以 了。

                  keeper分成兩大部分,第一部分為客戶端的javascript,第二部分是服務端的servlet和事件處理。

                  一.客戶端

                  建立一個XMLRequest對象池,每發送一次請求,從對象池中取一個XMLRequest對象,如果沒有可用的對象,則創建一 個,把它加入到對象池中。這部分的代碼來自于網絡。

                  為了使用方便,再添加一些方法,用來注冊事件。這樣只要調用注冊函數來注冊事件,并且把回調函數傳給注冊事件函數就行了,處理數據 的事情,交給回調函數,并由用戶來實現。

                  keeper為了方便使用,把客戶端的javascript代碼集成在servlet中,當配置好keeper的servlet, 啟動HTTP服務器時,keeper會根據用戶的配置,在相應的目錄下生成客戶端的javascript代碼。

              二.服務端

                  服務端的servlet初始化時,根據配置來生成相應的客戶端javascript代碼。

                  servlet的入口由keeper.servlet.Keeper.java中的doGet進入。在Keeper的doGet 中,從請求中獲取用戶注冊事件的名稱(字符串類型),然后根據事件的名稱,構造一個事件(Event類型),再把它注冊到NameRegister中,注 冊完成后,該servlet線程調用wait(),把自已停止。等待該servlet線程被喚醒后,從Event中調用事件的EventListener 接口的process(request,response)來處理客戶端的請求。

          1.     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          2.         String eventName = request.getParameter("event");
          3.         NameRegister reg = NameRegister.getInstance();
          4.         Event event = null;
          5.         try {
          6.             event = reg.getEvent(eventName);
          7.             if(event == null) {
          8.                 event = new Event(eventName,this);
          9.                 reg.registeEvent(eventName, event);
          10.             }
          11.             if(event.getServlet() == null) {
          12.                 event.setServlet(this);
          13.             }
          14.             
          15.         } catch (RegistException e1) {
          16.             e1.printStackTrace();
          17.         }
          18.         synchronized(this) {
          19.             while(!event.isProcess()) {
          20.                 try {
          21.                     wait();
          22.                 } catch (InterruptedException e) {
          23.                     e.printStackTrace();
          24.                 }
          25.             }
          26.         }
          27.         EventListener listener = event.getListener();
          28.         if(listener != null) {
          29.            listener.process(request,response);
          30.         }   
          31.     }

                  在服務端處理事件時,調用了keeper.control.Controller中的靜態方法 action(EventListener listener,String eventName)來處理。如下所示。

          1.     public static boolean action(EventListener listener,String eventName){
          2.         NameRegister reg = NameRegister.getInstance();
          3.         HttpServlet servlet = null;
          4.         Event e = null;
          5.         try {
          6.             e = reg.getEvent(eventName,true);
          7.             if(e == null) {
          8.                 return false;
          9.             }
          10.             e.setListener(listener);
          11.             servlet = e.getServlet();
          12.             e.setProcess(true);
          13.             synchronized(servlet) {
          14.                 servlet.notifyAll();
          15.             }
          16.         } catch (RegistException ex) {
          17.             ex.printStackTrace();
          18.             }
          19.         if(servlet != null && e != null) {
          20.             e = null;
          21.             return true;
          22.         } else {
          23.             return false;
          24.         }
          25.     }

          下面開始用keeper來寫一個簡單的網頁聊天程序和基于服務端的時間。

              1.客戶端設置

                  注冊兩個事件,一個用于是時間事件,一個是消息事件。同時還要寫兩個回調函數,用于處理服務 端返回的時間和聊天消息。如下所于:

          1. <script type="text/javascript">
          2.     Keeper.addListener('timer',showTime);//注冊時間事件
          3.     function showTime(obj){ //時間處理回調函數
          4.         var sp = document.getElementById("dateTime");
          5.         if(sp){
          6.             sp.innerHTML = obj.responseText;
          7.         }
          8.     }
          9.     function startOrStop(obj){
          10.         var btn = document.getElementById("controlBtn")
          11.         btn.value=obj.responseText;
          12.     }
          13.     Keeper.addListener('msg',showMsg,"GBK");//注冊消息事 件,最后一個參數是
          14. //字符串編碼
          15.     function showMsg(obj){//處理消息的回調函數
          16.         var msg = document.getElementById("msg");
          17.         if(msg){
          18.             
          19.                 msg.value = obj.responseText+""n"+msg.value;
          20.             
          21.         }
          22.     }
          23.     function sendMsg() {
          24.         var msg = document.getElementById("sendMsg");
          25.         if(msg){
          26.             var d = "msg="+msg.value;
          27.             sendReq('POST','./demo',d,startOrStop);
          28.             msg.value = "";
          29.         }
          30.     }
          31.     
          32. </script>

              2.配置服務端

              服務端的配置在 web.xml文件中,如下所示

          1.   <servlet>
          2.     <servlet-name>keeper</servlet-name>
          3.     <servlet-class>keeper.servlet.Keeper</servlet-class>
          4.     <init-param>
          5. <!--可選項,設置生成客戶端的JavaScript路徑和名字,默認置為 /keeper.js-->
          6.       <param-name>ScriptName</param-name>
          7.       <param-value>/keeperScript.js</param-value>
          8.     </init-param>
          9. <!--這個一定要設置,否則不能生成客戶端代碼-->
          10.     <load-on-startup>1</load-on-startup>
          11.   </servlet>
          12.   <servlet-mapping>
          13.     <servlet-name>keeper</servlet-name>
          14.     <url-pattern>/keeper</url-pattern>
          15.   </servlet-mapping>

                  用<script type="text/javascript" src="./keeperScript.js"></script>在頁面包含JavaScript時,這里的src一定要和上面配 置的一至。上面的設置除了<init-param></init-param>為可選的設置外,其他的都是必要的,而且不能改 變。

                  3.編寫事件處理代碼,消息的處理代碼如下:
          1.     protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          2.         System.out.println("Post..");
          3.         String msg = request.getParameter("msg");
          4.         Controller.action(new SendMsg(msg),"msg");
          5.     }
          1. class SendMsg implements EventListener{
          2.     private String msg;
          3.     public SendMsg(String msg) {
          4.         this.msg = msg;
          5.     }
          6.     @Override
          7.     public void process(HttpServletRequest request, HttpServletResponse response) {
          8.         response.setCharacterEncoding("UTF-8");
          9.         PrintWriter out = null;
          10.         try {
          11.             out = response.getWriter();
          12.             if(msg!=null){
          13.                 out.write(msg);
          14.             }
          15.         } catch (IOException e) {   
          16.             e.printStackTrace();
          17.         }
          18.         finally{
          19.             if(out != null) {
          20.                 out.close();
          21.             }
          22.         }       
          23.     }
          24. }

           到這時,一個基本的keeper應用就完成了。其它部分請參考附件中的例子源碼。


          posted on 2010-06-02 15:31 小菜毛毛 閱讀(3057) 評論(1)  編輯  收藏 所屬分類: java基礎運用

          Feedback

          # re: 用java實現comet,基于 HTTP長連接的實現,用于從服務端實時發送信息到客戶端 2014-06-10 10:42 趙迪生
          這不是掩耳盜鈴么  回復  更多評論
            

          主站蜘蛛池模板: 大厂| 梅州市| 合川市| 维西| 都安| 永寿县| 东乌珠穆沁旗| 牙克石市| 浦县| 昌都县| 进贤县| 富蕴县| 定远县| 张家港市| 襄城县| 黎川县| 杨浦区| 乾安县| 蒙城县| 秦皇岛市| 丰镇市| 大理市| 阳江市| 通化市| 安新县| 宣汉县| 通榆县| 桃江县| 鸡东县| 华池县| 恩施市| 礼泉县| 赤城县| 虞城县| 武功县| 新竹市| 如皋市| 嵊州市| 安丘市| 吉水县| 惠州市|