Using the nio connector from the latest 6.0.x trunk, I'm failing to receive any comet timeouts. I set the comet timeout to 5 secs but, after waiting much longer than 5 secs, the only two events I receive are begin and read.
event: BEGIN, subtype: null for servlet: com.seekspeak.server.debug.CometTestServlet time: Wed Jan 09 12:12:28 PST 2008 on cometEvent: [EMAIL PROTECTED] with "org.apache.tomcat.comet.timeout" attribute: null with "org.apache.tomcat.comet.timeout.support" attribute: true event: READ, subtype: null for servlet: com.seekspeak.server.debug.CometTestServlet time: Wed Jan 09 12:12:28 PST 2008 on cometEvent: [EMAIL PROTECTED] with "org.apache.tomcat.comet.timeout" attribute: 5000 with "org.apache.tomcat.comet.timeout.support" attribute: true I see that the Http11NioProcessor changed some comet timeout specific code from the previous rev. Could this be having an impact? Below is my test client and test servlet. Am I doing something wrong? Thanks, Peter SERVLET --------------- public class CometTestServlet extends HttpServlet implements CometProcessor { public void event(CometEvent cometEvent) throws IOException, ServletException { System.out.println("event: " + cometEvent.getEventType() + ", subtype: " + cometEvent.getEventSubType()); System.out.println("\tfor servlet: " + this.getClass().getName()); System.out.println("\ttime: " + new Date(System.currentTimeMillis())); System.out.println("\ton cometEvent: " + cometEvent); System.out.println("\twith \"org.apache.tomcat.comet.timeout\" attribute: " + cometEvent.getHttpServletRequest().getAttribute("org.apache.tomcat.comet.timeout")); System.out.println("\twith \"org.apache.tomcat.comet.timeout.support\" attribute: " + cometEvent.getHttpServletRequest().getAttribute("org.apache.tomcat.comet.timeout.support")); if (cometEvent.getEventType() == CometEvent.EventType.BEGIN) { cometEvent.setTimeout(5 * 1000); } else if (cometEvent.getEventType() == CometEvent.EventType.ERROR) { cometEvent.close(); } else if (cometEvent.getEventType() == CometEvent.EventType.END) { cometEvent.close(); } else if (cometEvent.getEventType() == CometEvent.EventType.READ) { handleReadEvent(cometEvent); } } private void handleReadEvent(CometEvent cometEvent) throws IOException, ServletException { ServerCometChannel talker = new ServerCometChannel(cometEvent); respond(talker); } private void respond(ServerCometChannel channel) throws IOException { String clientMessage = channel.receive(); if (clientMessage != null && clientMessage.length() > 0) { channel.send("comet succeeded"); } } private class ServerCometChannel { private static final int OUTPUT_BUFFER_SIZE = 512; private CometEvent cometEvent; private InputStream inputStream; private PrintWriter outputWriter; public ServerCometChannel(CometEvent cometEvent) throws IOException, ServletException { this.cometEvent = cometEvent; inputStream = cometEvent.getHttpServletRequest().getInputStream(); OutputStream outputStream = cometEvent.getHttpServletResponse().getOutputStream(); this.outputWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream), OUTPUT_BUFFER_SIZE)); } private String receive() throws IOException { StringBuffer buffer = new StringBuffer(); byte[] buf = new byte[512]; while (inputStream.available() > 0) { int n = inputStream.read(buf); if (n > 0) { buffer.append(new String(buf, 0, n)); } } return buffer.toString(); } public void send(String msg) { synchronized (cometEvent.getHttpServletResponse()) { outputWriter.print(msg); outputWriter.flush(); try { cometEvent.getHttpServletResponse().flushBuffer(); } catch (IOException ioe) { ioe.printStackTrace(); } } } } } CLIENT ---------- public class CometTest { public static void main(String[] args) throws Exception { CometTest test = new CometTest(); test.test(); } private void test() throws Exception { URL url = new URL("http://www.seekspeak.com/CometTest"); CometChannel channel = new CometChannel(url); channel.send("test"); String received = channel.receive(); System.out.println("received: " + received); Thread.sleep(60 * 60 * 1000); } private class CometChannel { private static final int INPUT_BUFFER_SIZE = 512; private static final int OUTPUT_BUFFER_SIZE = 512; private static final String DELIMITER = "\r\n"; private URL url; private BufferedReader inputReader; private PrintWriter outputWriter; private Socket socket; private boolean firstRead = true; public CometChannel(URL url) throws IOException { this.url = url; initConnection(); } private void initSocket() throws IOException { int port = url.getPort(); port = (port < 0) ? url.getDefaultPort() : port; try { socket = new Socket(url.getHost(), port); socket.setKeepAlive(true); inputReader = new BufferedReader(new InputStreamReader(socket.getInputStream()), INPUT_BUFFER_SIZE); outputWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()), OUTPUT_BUFFER_SIZE)); } catch (NoRouteToHostException nrthe) { System.out.println("host: " + url.getHost()); nrthe.printStackTrace(); } } private void initConnection() throws IOException { initSocket(); sendHeaders(); } private void sendHeaders() { String path = url.getPath(); StringBuffer outputBuffer = new StringBuffer(); outputBuffer.append("POST " + path + " HTTP/1.1" + DELIMITER); outputBuffer.append("Host: " + url.getHost() + DELIMITER); outputBuffer.append("User-Agent: CometTestApplet" + DELIMITER); outputBuffer.append("Connection: keep-alive" + DELIMITER); outputBuffer.append("Content-Type: text/plain" + DELIMITER); outputBuffer.append("Transfer-Encoding: chunked" + DELIMITER); outputBuffer.append(DELIMITER); synchronized (outputWriter) { outputWriter.print(outputBuffer.toString()); } } public void send(String chunkData) throws IOException { String hexChunkLength = Integer.toHexString(chunkData.length()); StringBuffer outputBuffer = new StringBuffer(); outputBuffer.append(hexChunkLength); outputBuffer.append(DELIMITER); outputBuffer.append(chunkData); outputBuffer.append(DELIMITER); synchronized (outputWriter) { outputWriter.print(outputBuffer.toString()); outputWriter.flush(); } } private String readChunk() throws IOException { StringBuffer inputBuffer = new StringBuffer(); String hexChunkSize = inputReader.readLine(); System.out.println("chunk size: " + hexChunkSize); if (hexChunkSize != null) { int chunkSize = Integer.parseInt(hexChunkSize, 16); int charsRead = 0; char[] buf = new char[chunkSize]; do { int n = inputReader.read(buf); charsRead += n; if (n > 0) { inputBuffer.append(new String(buf, 0, n)); } else if (n < 0) { // occurs when connection is closed, often in response // to http session timeout from server throw new IOException("no bytes read"); } } while (charsRead < chunkSize); // extra \r\n sent after chunk - part of protocol inputReader.readLine(); } return inputBuffer.toString(); } public String receive() throws IOException { if (firstRead) { firstRead = false; readHeaders(); } return readChunk(); } private void readHeaders() throws IOException { String header; while ((header = inputReader.readLine()) != null) { System.out.println("header: " + header); if (header.length() == 0) { break; } } } } } On Jan 7, 2008 4:43 PM, Filip Hanik - Dev Lists <[EMAIL PROTECTED]> wrote: > The time when it is called without a subtype, is if the > application(servlet) has an unhandled exception > > in terms of timeout, that should work just dandy, unless the client > disconnects, at which point at which point you might get a subtype of > IOEXCEPTION, or CLIENT_DISCONNECT > depending on the OS > > Filip > > > Peter Warren wrote: > > Using the NIO connector: > > protocol="org.apache.coyote.http11.Http11NioProtocol". > > > > I'll add response.flushBuffer() and see if that helps. > > > > The tomcat version I was testing against was current with svn as of > > last Friday. I just updated and the only files that are new are: > > catalina.policy > > STATUS.txt > > changelog.xml > > > > Any ideas about the timeout setting or the comet error event without a > > subtype? > > > > Thanks for your response! > > > > Peter > > > > On Jan 7, 2008 12:44 PM, Filip Hanik - Dev Lists <[EMAIL PROTECTED]> wrote: > > > >> what connector are you using? > >> I would try to use response.flushBuffer when you wanna flush it out (ie > >> after you've written to and flushed your stream). > >> > >> also, there have been some bug fixes, that you can get from SVN, or wait > >> for 6.0.16 to come out > >> > >> Filip > >> > >> > >> Peter Warren wrote: > >> > >>> I have some comet questions. I'm using the tomcat 6.0.x trunk as of > >>> last Friday. > >>> > >>> 1) My comet event timeout setting being honored. How come? I set the > >>> timeout for 3 hours but a timeout event gets generated every 2 > >>> minutes. If I inspect the comet event for which the timeout is > >>> triggered, I see a setting for the request attribute of: > >>> org.apache.tomcat.comet.timeout=10800000. > >>> > >>> I set it as follows: > >>> > >>> public void event(CometEvent cometEvent) throws IOException, > >>> ServletException { > >>> ... > >>> if (cometEvent.getEventType() == CometEvent.EventType.BEGIN) { > >>> // COMET_TIMEOUT = 3 * 60 * 60 * 1000 > >>> cometEvent.setTimeout(TimingConstants.COMET_TIMEOUT); > >>> > >>> Do I need to set something else as well? > >>> > >>> 2) Occasionally I'm getting a comet event of type ERROR without any > >>> subtype (i.e. not TIMEOUT, CLIENT_DISCONNECT, etc.). What does that > >>> indicate? I don't see any errors in my catalina log. > >>> > >>> 3) Reading the response from a comet servlet fails for one of my > >>> client machines. I wrote a simple test to check the problem. This > >>> test succeeds for many other users. For the failing client, the > >>> client request is received by the comet servlet, and the servlet's > >>> response is written and flushed to the stream. The client then simply > >>> waits indefinitely trying to read the response. The failing client is > >>> a Windows XP machine. Could anyone shed some light on why this might > >>> be happening, or give me some clues as to how to debug? Could it be a > >>> firewall issue on the client end, a router issue on my end? > >>> > >>> The test is currently up at: http://www.seekspeak.com/test.html. It > >>> tests: a http connection to a normal servlet, then a comet connection > >>> to a comet servlet using httpurlconnection, then a comet connection to > >>> a comet servlet using a socket. For the failing client, both comet > >>> tests fail. > >>> > >>> Below is some of the test code for the raw socket test. > >>> > >>> Thanks for any help! > >>> > >>> Peter > >>> > >>> CLIENT > >>> ------ > >>> private void testCometConnection() throws IOException { > >>> ... > >>> URL url = new URL("http://www.seekspeak.com/CometTest"); > >>> channel = new CometChannel(url); > >>> Thread testThread = new Thread() { > >>> public void run() { > >>> try { > >>> channel.send("test"); > >>> String received = channel.receive(); > >>> ... > >>> } > >>> } catch (IOException ioe) { > >>> ioe.printStackTrace(); > >>> } > >>> } > >>> }; > >>> testThread.start(); > >>> ... > >>> } > >>> > >>> private class CometChannel { > >>> > >>> private static final int INPUT_BUFFER_SIZE = 512; > >>> > >>> private static final int OUTPUT_BUFFER_SIZE = 512; > >>> > >>> private static final String DELIMITER = "\r\n"; > >>> > >>> private URL url; > >>> > >>> private BufferedReader inputReader; > >>> > >>> private PrintWriter outputWriter; > >>> > >>> private Socket socket; > >>> > >>> public CometChannel(URL url) throws IOException { > >>> this.url = url; > >>> initConnection(); > >>> } > >>> > >>> private void initSocket() throws IOException { > >>> int port = url.getPort(); > >>> port = (port < 0) ? url.getDefaultPort() : port; > >>> try { > >>> socket = new Socket(url.getHost(), port); > >>> socket.setKeepAlive(true); > >>> inputReader = new BufferedReader(new > >>> InputStreamReader(socket.getInputStream()), INPUT_BUFFER_SIZE); > >>> outputWriter = new PrintWriter(new BufferedWriter(new > >>> OutputStreamWriter(socket.getOutputStream()), > >>> OUTPUT_BUFFER_SIZE)); > >>> } catch (NoRouteToHostException nrthe) { > >>> System.out.println("host: " + url.getHost()); > >>> nrthe.printStackTrace(); > >>> } > >>> } > >>> > >>> private void initConnection() throws IOException { > >>> initSocket(); > >>> sendHeaders(); > >>> } > >>> > >>> private void sendHeaders() { > >>> String path = url.getPath(); > >>> StringBuffer outputBuffer = new StringBuffer(); > >>> outputBuffer.append("POST " + path + " HTTP/1.1" + DELIMITER); > >>> outputBuffer.append("Host: " + url.getHost() + DELIMITER); > >>> outputBuffer.append("User-Agent: CometTestApplet" + > >>> DELIMITER); > >>> outputBuffer.append("Connection: keep-alive" + DELIMITER); > >>> outputBuffer.append("Content-Type: text/plain" + DELIMITER); > >>> outputBuffer.append("Transfer-Encoding: chunked" + DELIMITER); > >>> outputBuffer.append(DELIMITER); > >>> synchronized (outputWriter) { > >>> outputWriter.print(outputBuffer.toString()); > >>> } > >>> } > >>> > >>> public void send(String chunkData) throws IOException { > >>> // chunk length field in hex > >>> String hexChunkLength = > >>> Integer.toHexString(chunkData.length()); > >>> > >>> StringBuffer outputBuffer = new StringBuffer(); > >>> outputBuffer.append(hexChunkLength); > >>> outputBuffer.append(DELIMITER); > >>> outputBuffer.append(chunkData); > >>> outputBuffer.append(DELIMITER); > >>> synchronized (outputWriter) { > >>> outputWriter.print(outputBuffer.toString()); > >>> outputWriter.flush(); > >>> } > >>> } > >>> > >>> private String readChunk() throws IOException { > >>> StringBuffer inputBuffer = new StringBuffer(); > >>> String hexChunkSize = inputReader.readLine(); > >>> if (hexChunkSize != null) { > >>> int chunkSize = Integer.parseInt(hexChunkSize, 16); > >>> int charsRead = 0; > >>> > >>> char[] buf = new char[chunkSize]; > >>> do { > >>> int n = inputReader.read(buf); > >>> charsRead += n; > >>> if (n > 0) { > >>> inputBuffer.append(new String(buf, 0, n)); > >>> } else if (n < 0) { > >>> // occurs when connection is closed, often in > >>> response > >>> // to http session timeout from server > >>> throw new IOException("no bytes read"); > >>> } > >>> } while (charsRead < chunkSize); > >>> // extra \r\n sent after chunk - part of protocol > >>> inputReader.readLine(); > >>> } > >>> return inputBuffer.toString(); > >>> } > >>> > >>> public String receive() throws IOException { > >>> readHeaders(); > >>> return readChunk(); > >>> } > >>> > >>> private void readHeaders() throws IOException { > >>> String header; > >>> while ((header = inputReader.readLine()) != null) { > >>> System.out.println("header: " + header); > >>> if (header.length() == 0) { > >>> break; > >>> } > >>> } > >>> } > >>> ... > >>> } > >>> > >>> SERVER > >>> ------ > >>> public class CometTestServlet extends HttpServlet implements > >>> CometProcessor { > >>> private static final long serialVersionUID = 5472498184127924791L; > >>> > >>> public void event(CometEvent cometEvent) throws IOException, > >>> ServletException { > >>> HttpServletRequest request = cometEvent.getHttpServletRequest(); > >>> HttpSession httpSession = request.getSession(true); > >>> if (cometEvent.getEventType() == CometEvent.EventType.BEGIN) { > >>> cometEvent.setTimeout(3 * 60 * 60 * 1000); // 3 hours > >>> // tell the http session not to timeout - will invalidate it > >>> on > >>> // error or end > >>> httpSession.setMaxInactiveInterval(-1); > >>> } else if (cometEvent.getEventType() == > >>> CometEvent.EventType.ERROR) { > >>> handleErrorEvent(cometEvent, httpSession); > >>> } else if (cometEvent.getEventType() == CometEvent.EventType.END) > >>> { > >>> close(cometEvent, httpSession); > >>> } else if (cometEvent.getEventType() == > >>> CometEvent.EventType.READ) { > >>> handleReadEvent(cometEvent); > >>> } > >>> } > >>> > >>> protected void handleErrorEvent(CometEvent cometEvent, HttpSession > >>> httpSession) throws IOException { > >>> if (cometEvent.getEventSubType() != > >>> CometEvent.EventSubType.TIMEOUT) { > >>> close(cometEvent, httpSession); > >>> } > >>> } > >>> > >>> private void close(CometEvent cometEvent, HttpSession httpSession) > >>> throws IOException { > >>> cometEvent.close(); > >>> httpSession.invalidate(); > >>> } > >>> > >>> private void handleReadEvent(CometEvent cometEvent) throws > >>> IOException, ServletException { > >>> ServerCometChannel talker = new ServerCometChannel(cometEvent); > >>> respond(talker); > >>> } > >>> > >>> private void respond(ServerCometChannel channel) throws IOException { > >>> String clientMessage = channel.receive(); > >>> > >>> if (clientMessage != null && clientMessage.length() > 0) { > >>> channel.send("comet succeeded"); > >>> } > >>> } > >>> > >>> private class ServerCometChannel { > >>> > >>> private static final int OUTPUT_BUFFER_SIZE = 512; > >>> > >>> private CometEvent cometEvent; > >>> > >>> private InputStream inputStream; > >>> > >>> private PrintWriter outputWriter; > >>> > >>> public ServerCometChannel(CometEvent cometEvent) throws > >>> IOException, ServletException { > >>> this.cometEvent = cometEvent; > >>> inputStream = > >>> cometEvent.getHttpServletRequest().getInputStream(); > >>> OutputStream outputStream = > >>> cometEvent.getHttpServletResponse().getOutputStream(); > >>> this.outputWriter = new PrintWriter(new BufferedWriter(new > >>> OutputStreamWriter(outputStream), > >>> OUTPUT_BUFFER_SIZE)); > >>> } > >>> > >>> private String receive() throws IOException { > >>> StringBuffer buffer = new StringBuffer(); > >>> byte[] buf = new byte[512]; > >>> while (inputStream.available() > 0) { > >>> int n = inputStream.read(buf); > >>> if (n > 0) { > >>> buffer.append(new String(buf, 0, n)); > >>> } > >>> } > >>> return buffer.toString(); > >>> } > >>> > >>> public void send(String msg) { > >>> synchronized (cometEvent.getHttpServletResponse()) { > >>> outputWriter.print(msg); > >>> outputWriter.flush(); > >>> } > >>> } > >>> > >>> public void close() throws IOException { > >>> inputStream.close(); > >>> outputWriter.close(); > >>> } > >>> } > >>> > >>> --------------------------------------------------------------------- > >>> To start a new topic, e-mail: users@tomcat.apache.org > >>> To unsubscribe, e-mail: [EMAIL PROTECTED] > >>> For additional commands, e-mail: [EMAIL PROTECTED] > >>> > >>> > >>> > >>> > >>> > >> --------------------------------------------------------------------- > >> To start a new topic, e-mail: users@tomcat.apache.org > >> To unsubscribe, e-mail: [EMAIL PROTECTED] > >> For additional commands, e-mail: [EMAIL PROTECTED] > >> > >> > >> > > > > --------------------------------------------------------------------- > > To start a new topic, e-mail: users@tomcat.apache.org > > To unsubscribe, e-mail: [EMAIL PROTECTED] > > For additional commands, e-mail: [EMAIL PROTECTED] > > > > > > > > > > > --------------------------------------------------------------------- > To start a new topic, e-mail: users@tomcat.apache.org > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > > --------------------------------------------------------------------- To start a new topic, e-mail: users@tomcat.apache.org To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]