Anyone else experiencing comet timeout problems with the nio connector and the latest 6.0.x trunk?
My cometEvent.setTimeout(...) setting is ignored, but I do receive comet timeouts based on the connectionTimeout setting for the nio connector. Setting the connectionTimeout to 10 secs gives me a comet timeout event every 10 secs. Setting it to 2 mins gives a comet timeout every 2 mins. The docs don't mention any link between the connectionTimeout settings and comet timeout events that I can find. Connector config: <Connector port="80" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="500" connectionTimeout="10000" keepAliveTimeout="30000" maxKeepAliveRequests="-1" socket.soKeepAlive="true" socket.appReadBufSize="2048" socket.appWriteBufSize="2048" socket.rxBufSize="2048" socket.txBufSize="2048" acceptorThreadCount="2" redirectPort="8443" /> On Jan 9, 2008 12:23 PM, Peter Warren <[EMAIL PROTECTED]> wrote: > 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]