2009-07-13 10 views
2

Ich schreibe gerade eine Comet-Anwendung, die es mir erfordert, Datenblöcke gleichzeitig auf einer persistenten Verbindung zu senden. Ich habe jedoch Probleme beim Löschen der Nachricht an den Client vor dem Schließen der Verbindung. Gibt es einen Grund dafür, dass sich die PrintWriter.flush() -Methode nicht so verhält, wie ich denke?Java-Servlets: Warum wird PrintWriter.flush() nicht gespült?

Dies ist meine Tomcat Comet Implementierung:

public void event(CometEvent event) throws IOException, ServletException { 
    HttpServletRequest request = event.getHttpServletRequest(); 
    HttpServletResponse response = event.getHttpServletResponse(); 
    if (event.getEventType() == EventType.BEGIN) { 
     request.setAttribute("org.apache.tomcat.comet.timeout", 300 * 1000); 
     PrintWriter out = response.getWriter(); 
     out.println("BEGIN!"); 
     out.flush(); 
     System.out.println("EventType.BEGIN"); 
    } else if (event.getEventType() == EventType.READ) { 
     InputStream is = request.getInputStream(); 
     byte[] buf = new byte[512]; 
     do { 
      int n = is.read(buf); //can throw an IOException 
      if (n > 0) { 
       System.out.println("Read " + n + " bytes: " + new String(buf, 0, n) 
         + " for session: " + request.getSession(true).getId()); 
      } else if (n < 0) { 

       return; 
      } 
     } while (is.available() > 0); 
     System.out.println("subtype: "+event.getEventSubType()); 
     System.out.println("EventType.READ"); 
    } else if (event.getEventType() == EventType.END) { 
     PrintWriter out = response.getWriter(); 
     out.println("END!"); 
     out.close(); 
     System.out.println("checkError: "+out.checkError()); 
     System.out.println(event.getEventSubType()); 
     System.out.println("EventType.END"); 
     //eventWorker.enqueue(new EndEvent(request, response)); 
    } else if (event.getEventType() == EventType.ERROR) { 
     PrintWriter out = response.getWriter(); 

     out.println("ERROR!"); 
     out.flush(); 
     System.out.println("checkError: "+out.checkError()); 
     System.out.println("subtype: "+event.getEventSubType()); 

     //response.getWriter().close(); 
     System.out.println("EventType.ERROR"); 
    } else { 
     (new ServletException("EXCEPTION")).printStackTrace(); 
    } 
} 

Also hier die Nachricht Ich versuche zu senden "BEGIN!" und halte die Verbindung danach offen, damit ich mehr Daten senden kann. Es scheint jedoch, dass die Nachricht nicht ausgeführt wird, bis die Verbindung geschlossen ist.

Das ist mein Ajax-Code: $ .post ('Komet', Funktion (Daten) {Alarm (Daten);});

Nachdem ich diesen Code ausführen, Firebug sagt mir, dass dies die Antwort-Header: Server: Apache-Coyote/1.1 Transfer-Encoding: Chunked Datum: Mo, 13. Juli 2009 21.16.29 GMT

Das führt mich zu der Annahme, dass mein Browser einige Daten zurück erhalten hat, aber wie aktualisiere ich etwas auf der Seite, bevor die Verbindung geschlossen wird?

Antwort

3

So scheint es, dass der Browser die ganze Zeit Daten empfangen hat, aber da die Verbindung nicht geschlossen wurde, wurden die JavaScript-Gedanken noch gesendet. Aus diesem Grund wurde meine jQuery-Callback-Funktion nicht aufgerufen.

Mit Blick auf das W3C AJAX-Tutorial habe ich festgestellt, dass es verschiedene Bereitzustände für das XMLHttpRequest-Objekt gibt.

var xmlhttp; 
    if (window.XMLHttpRequest) 
     { 
     // code for IE7+, Firefox, Chrome, Opera, Safari 
     xmlhttp=new XMLHttpRequest(); 
     } 
    else if (window.ActiveXObject) 
     { 
     // code for IE6, IE5 
     xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); 
     } 
    else 
     { 
     alert("Your browser does not support XMLHTTP!"); 
     } 
    xmlhttp.onreadystatechange=function() 
    { 
     if(xmlhttp.readyState==3) { 
      alert('process '+xmlhttp.responseText); 
     } 
     if(xmlhttp.readyState==4) { 
      alert('ready '+xmlhttp.responseText); 
     } 
    } 
    xmlhttp.open("GET","comet",true); 
    xmlhttp.send(null); 

Traditionell behandeln Menschen nur den 4. Readystate, was bedeutet, Übertragung abgeschlossen ist. In meinem Fall musste ich jedoch Daten lesen, bevor die Übertragung beendet wurde. Daher brauchte ich Code, um den 3. readyState zu handhaben.

0

Ich erinnere mich, dass es ein Problem mit Servlets gibt, wo, wenn Ihre Seite umgeleitet wird (wie eine Fehlerseite), der aktuelle Antwortpuffer, writer in diesem Fall, weggeworfen wird, ohne geschrieben zu werden.

0

Ich folge nicht wirklich der Pointe.

Sobald ein Fehler auftritt und die Verbindung geschlossen wird, werden alle Nachrichten angezeigt, die ich zuvor gesendet habe.

was bedeutet das? Vielleicht möchten Sie auch die API für verfügbar(). Ich glaube nicht, dass es das tut, was du denkst.

+0

Also hier versuche ich die Nachricht "BEGINN!" und halte die Verbindung danach offen, damit ich mehr Daten senden kann. Es scheint jedoch, dass die Nachricht nicht ausgeführt wird, bis die Verbindung geschlossen ist. – jcee14

+1

Ok, versuche response.flushBuffer()? Wenn das nicht funktioniert, versuchen Sie eine Tonne mehr Bytes zu schreiben. Welchen Anschluss verwenden Sie APR oder NIO? Sollte nicht Firebug dir auch sagen, was in der Antwort ist? Es sieht so aus, als ob Sie nur die Antwortheader erhalten. –

0

hatte ich fast das gleiche Problem:

Beide Anrufe und nichts ausgehen.

writer.flush(); 
writer.end(); 

Als ich oben eine response.flushBuffer() zusätzlich zu den beiden zu tun versuchte, wurde ein java.nio.charset.UnmappableCharacterException (unter Jboss 5.1) geworfen. Ich habe dann eine response.setCharacterEncoding("UTF-8); hinzugefügt und das Problem ist weg.

Dies hat wahrscheinlich nichts mit Ihrem Problem zu tun, aber da ich Ihren Beitrag als der erste in Google gefunden habe, beantworte ich es hier für Menschen mit der gleichen Situation.