Hi Filip,
Somehow I missed your response a while back. Below are two test clients
and one comet servlet. One client works, and the other doesn't. I
found out the failing client doesn't work because HttpURLConnection
doesn't seem to allow writing to the output stream after the input
stream has been requested (or at least I haven't figured out how to
allow it). On the other hand, Filip cautioned me against using the
client that works because it re-sends http headers with each request,
which could potentially get received as data by the comet servlet.
So... is there a way for me to use a single HttpURLConnection and be
able to read and write multiple times on its input and output streams?
I tried setting Transfer-Encoding to chunked, but couldn't get it to
make a difference. I'd like to use HttpURLConnection instead of raw
sockets to avoid having to manually handle the headers, redirects,
proxies, etc. I realize this question is more java api specific than
tomcat comet specific, but since many comet users might like to use
HttpURLConnection, I thought it was still relevant here.
Thanks for any help,
Peter
### CometTestClient1.java - this test hangs since 2nd output on
HttpURLConnection doesn't get sent ###
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
public class CometTestClient1 {
private HttpURLConnection urlConn;
private PrintWriter out;
private URL url = new URL("http://127.0.0.1/CometTest");
public static void main(String[] args) throws Exception {
CometTestClient1 test = new CometTestClient1();
test.test();
}
public CometTestClient1() throws IOException {
initConnection();
}
private void initConnection() throws IOException {
urlConn = (HttpURLConnection) url.openConnection();
urlConn.setDoInput(true);
urlConn.setDoOutput(true);
urlConn.connect();
out = new PrintWriter(urlConn.getOutputStream());
}
public void test() throws IOException {
out.println("test 1");
out.flush();
String line = read(urlConn.getInputStream());
System.out.println(line);
// next line never gets sent out -- presumably because the url
connection
// doesn't allow output after getInputStream has been called
out.println("test 2");
out.flush();
line = read(urlConn.getInputStream());
System.out.println(line);
out.close();
urlConn.disconnect();
}
private String read(InputStream is) throws IOException {
StringBuffer inputBuffer = new StringBuffer();
byte[] buf = new byte[512];
do {
int n = is.read(buf); // can throw an IOException
if (n > 0) {
inputBuffer.append(new String(buf, 0, n));
} else if (n < 0) {
return ("read error");
}
} while (is.available() > 0);
return inputBuffer.toString();
}
}
### CometTestClient2.java - works but sends new http headers for each
client output ###
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
public class CometTestClient2 {
private HttpURLConnection urlConn;
private PrintWriter out;
private URL url = new URL("http://127.0.0.1/CometTest");
public static void main(String[] args) throws Exception {
CometTestClient2 test = new CometTestClient2();
test.test();
}
public CometTestClient2() throws IOException {
initConnection();
}
private void initConnection() throws IOException {
urlConn = (HttpURLConnection) url.openConnection();
urlConn.setDoInput(true);
urlConn.setDoOutput(true);
urlConn.connect();
out = new PrintWriter(urlConn.getOutputStream());
}
public void test() throws IOException {
out.println("test 1");
out.flush();
BufferedReader in = new BufferedReader(new
InputStreamReader(urlConn.getInputStream()));
String line = in.readLine();
System.out.println(line);
initConnection();
out.println("test 2");
out.flush();
in = new BufferedReader(new
InputStreamReader(urlConn.getInputStream()));
line = in.readLine();
System.out.println(line);
out.close();
urlConn.disconnect();
}
}
### CometTestServlet ###
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.CometEvent;
import org.apache.catalina.CometProcessor;
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();
HttpServletResponse response = cometEvent.getHttpServletResponse();
// don't want timeout events
cometEvent.setTimeout(1000000);
if (cometEvent.getEventType() == CometEvent.EventType.BEGIN) {
log("Begin for session: " + request.getSession(true).getId());
respond(request, response);
} else if (cometEvent.getEventType() ==
CometEvent.EventType.ERROR) {
log("Error for session: " + request.getSession(true).getId()
+ ", " + cometEvent.getEventSubType());
cometEvent.close();
} else if (cometEvent.getEventType() == CometEvent.EventType.END) {
log("End for session: " + request.getSession(true).getId());
cometEvent.close();
} else if (cometEvent.getEventType() == CometEvent.EventType.READ) {
log("Read for session: " + request.getSession(true).getId());
respond(request, response);
}
}
private void respond(HttpServletRequest request, HttpServletResponse
response) throws IOException {
String clientMessage = read(request);
if (clientMessage != null && clientMessage.length() > 0) {
response.getWriter().println(clientMessage);
response.getWriter().flush();
}
}
private String read(HttpServletRequest request) throws IOException {
InputStream is = request.getInputStream();
StringBuffer inputBuffer = new StringBuffer();
byte[] buf = new byte[512];
do {
int n = is.read(buf); // can throw an IOException
if (n > 0) {
inputBuffer.append(new String(buf, 0, n));
log("Read " + n + " bytes: " + new String(buf, 0, n) + "
for session: "
+ request.getSession(true).getId());
} else if (n < 0) {
log("comet read error");
}
} while (is.available() > 0);
return inputBuffer.toString();
}
}
Filip Hanik - Dev Lists wrote:
> why don't you make your test available, I'll run it through
>
> Filip
>
> Peter Warren wrote:
>> Yes, I'm using the NIO connector. Here is the config line from my
>> server.xml:
>>
>> <Connector port="80"
>> protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150"
>> connectionTimeout="20000" keepAliveTimeout="120000"
>> maxKeepAliveRequests="-1" acceptorThreadCount="2" redirectPort="8443" />
>>
>> Are there any other configuration options I need to set?
>>
>> Peter
>>
>> Filip Hanik - Dev Lists wrote:
>>
>>> and you are using the APR or the NIO connector right?
>>>
>>> Filip
>>>
>>> Peter Warren wrote:
>>>
>>>> Thanks for the suggestion. I changed the comet test servlet to read
>>>> directly from the input stream as shown in the advanced io
>>>> example. I'm
>>>> still seeing the same behavior. No comet read event gets generated on
>>>> the server, only the begin event which contains the client's first
>>>> message. The client then sends its second message and blocks waiting
>>>> for the server. No events are generated on the server in response to
>>>> the client's second message. Any other tips for me?
>>>>
>>>> Thanks,
>>>> Peter
>>>>
>>>> from the CometTestServlet:
>>>>
>>>> public void event(CometEvent cometEvent) throws IOException,
>>>> ServletException {
>>>> ...
>>>> if (cometEvent.getEventType() == CometEvent.EventType.BEGIN) {
>>>> log("Begin for session: " +
>>>> request.getSession(true).getId());
>>>> String clientMessage = read(request);
>>>> if (clientMessage != null && clientMessage.length() > 0) {
>>>> response.getWriter().println(clientMessage);
>>>> response.getWriter().flush();
>>>> }
>>>> }
>>>> ...
>>>>
>>>> private String read(HttpServletRequest request) throws
>>>> IOException {
>>>> InputStream is = request.getInputStream();
>>>> StringBuffer inputBuffer = new StringBuffer();
>>>> byte[] buf = new byte[512];
>>>> do {
>>>> int n = is.read(buf); // can throw an IOException
>>>> if (n > 0) {
>>>> inputBuffer.append(new String(buf, 0, n));
>>>> log("Read " + n + " bytes: " + new String(buf, 0,
>>>> n) + "
>>>> for session: "
>>>> + request.getSession(true).getId());
>>>> } else if (n < 0) {
>>>> log("comet read error");
>>>> }
>>>> } while (is.available() > 0);
>>>> return inputBuffer.toString();
>>>> }
>>>>
>>>> from the CometTestClient:
>>>>
>>>> public void test() throws IOException {
>>>> out.println("test 1");
>>>> out.flush();
>>>>
>>>> String line = read(urlConn.getInputStream());
>>>> System.out.println(line);
>>>>
>>>> out.println("test 2");
>>>> out.flush();
>>>>
>>>> line = read(urlConn.getInputStream());
>>>> System.out.println(line);
>>>>
>>>> out.close();
>>>> urlConn.disconnect();
>>>> }
>>>>
>>>> private String read(InputStream is) throws IOException {
>>>> StringBuffer inputBuffer = new StringBuffer();
>>>> byte[] buf = new byte[512];
>>>> do {
>>>> int n = is.read(buf); // can throw an IOException
>>>> if (n > 0) {
>>>> inputBuffer.append(new String(buf, 0, n));
>>>> } else if (n < 0) {
>>>> return ("read error");
>>>> }
>>>> } while (is.available() > 0);
>>>> return inputBuffer.toString();
>>>> }
>>>>
>>>> Filip Hanik - Dev Lists wrote:
>>>>
>>>>
>>>>> take a look at the documentation, the way you are reading it is
>>>>> incorrect.
>>>>> you need to take advantage of the available() method
>>>>>
>>>>> Filip
>>>>>
>>>>> Peter Warren wrote:
>>>>>
>>>>>> My BEGIN block in my comet servlet now looks like the code below
>>>>>> (added
>>>>>> a while loop to read until the buffer is empty). Is that what
>>>>>> you had
>>>>>> in mind? The buffer in the BEGIN event only contains the client's
>>>>>> first
>>>>>> message. Am I not emptying the buffer correctly? Although, I
>>>>>> wouldn't
>>>>>> expect the buffer to contain the client's second message since the
>>>>>> client blocks for an ack from the server before sending its second
>>>>>> message. Any other thoughts on what happens to the client's second
>>>>>> message and why no READ event is generated?
>>>>>>
>>>>>> Thanks for your help,
>>>>>> Peter
>>>>>>
>>>>>> if (cometEvent.getEventType() ==
>>>>>> CometEvent.EventType.BEGIN) {
>>>>>> log("Begin for session: " +
>>>>>> request.getSession(true).getId());
>>>>>> BufferedReader reader =
>>>>>> cometEvent.getHttpServletRequest().getReader();
>>>>>> String line = null;
>>>>>> while ((line = reader.readLine()) != null) {
>>>>>> log("servlet received: " + line);
>>>>>>
>>>>>> cometEvent.getHttpServletResponse().getWriter().println("servlet
>>>>>> received: " + line);
>>>>>>
>>>>>> cometEvent.getHttpServletResponse().getWriter().flush();
>>>>>> }
>>>>>> }
>>>>>>
>>>>>>
>>>>>>
>>>>>>> Filip Hanik wrote:
>>>>>>>
>>>>>>> it could be because the data from the request already came in with
>>>>>>> the
>>>>>>>
>>>>>> request.
>>>>>>
>>>>>>
>>>>>>> when the BEGIN happens, perform the actions as if there was a
>>>>>>> READ as
>>>>>>>
>>>>>> well, ie, empty out the buffer.
>>>>>>
>>>>>>
>>>>>>> Filip
>>>>>>>
>>>>>> Peter Warren wrote:
>>>>>>
>>>>>>
>>>>>>> The following client code generates a comet BEGIN event on the
>>>>>>> server
>>>>>>> but not a subsequent READ event, as I was expecting. How come?
>>>>>>> Is my
>>>>>>> code wrong? Are my expectations wrong? See sequence of events
>>>>>>> commented in code below.
>>>>>>>
>>>>>>> // client test method that sends messages to server and
>>>>>>> listens for
>>>>>>> responses
>>>>>>> public void test() throws IOException {
>>>>>>> out.println("test 1");
>>>>>>> out.flush();
>>>>>>>
>>>>>>> // server receives client's message, generates a BEGIN
>>>>>>> event,
>>>>>>> and sends response to client
>>>>>>>
>>>>>>> in = new BufferedReader(new
>>>>>>> InputStreamReader(urlConn.getInputStream()));
>>>>>>> System.out.println(in.readLine());
>>>>>>>
>>>>>>> // client receives server's response and prints it
>>>>>>>
>>>>>>> out.println("test 2");
>>>>>>> out.flush();
>>>>>>>
>>>>>>> System.out.println(in.readLine());
>>>>>>>
>>>>>>> // client code blocks here waiting for server response.
>>>>>>> // server never generates a READ event. How come?
>>>>>>> // Does the HttpURLConnection (see full code below) need
>>>>>>> to be
>>>>>>> set up differently?
>>>>>>> // Am I using the PrintWriter incorrectly when sending
>>>>>>> to the
>>>>>>> comet servlet?
>>>>>>>
>>>>>>> out.close();
>>>>>>> urlConn.disconnect();
>>>>>>> }
>>>>>>>
>>>>>>> Thanks for any help,
>>>>>>> Peter
>>>>>>>
>>>>>>> -- system --
>>>>>>>
>>>>>>> using:
>>>>>>> tomcat 6.0.13 on windows xp sp 2
>>>>>>> java 1.6.0_01
>>>>>>>
>>>>>>> -- test client & comet servlet source below --
>>>>>>>
>>>>>>> ## begin test client ##
>>>>>>>
>>>>>>> import java.io.BufferedReader;
>>>>>>> import java.io.IOException;
>>>>>>> import java.io.InputStreamReader;
>>>>>>> import java.io.PrintWriter;
>>>>>>> import java.net.HttpURLConnection;
>>>>>>> import java.net.URL;
>>>>>>>
>>>>>>> public class CometTestClient {
>>>>>>>
>>>>>>> private HttpURLConnection urlConn;
>>>>>>>
>>>>>>> private PrintWriter out;
>>>>>>>
>>>>>>> private BufferedReader in;
>>>>>>>
>>>>>>> public static void main(String[] args) throws Exception {
>>>>>>> CometTestClient test = new CometTestClient();
>>>>>>> test.test();
>>>>>>> }
>>>>>>>
>>>>>>> public CometTestClient() throws IOException {
>>>>>>> initConnection();
>>>>>>> }
>>>>>>>
>>>>>>> private void initConnection() throws IOException {
>>>>>>> URL url = new URL("http://127.0.0.1/CometTest");
>>>>>>> urlConn = (HttpURLConnection) url.openConnection();
>>>>>>> urlConn.setDoInput(true);
>>>>>>> urlConn.setDoOutput(true);
>>>>>>> urlConn.connect();
>>>>>>> out = new PrintWriter(urlConn.getOutputStream());
>>>>>>> }
>>>>>>>
>>>>>>> public void test() throws IOException {
>>>>>>> out.println("test 1");
>>>>>>> out.flush();
>>>>>>>
>>>>>>> in = new BufferedReader(new
>>>>>>> InputStreamReader(urlConn.getInputStream()));
>>>>>>> System.out.println(in.readLine());
>>>>>>>
>>>>>>> out.println("test 2");
>>>>>>> out.flush();
>>>>>>>
>>>>>>> System.out.println(in.readLine());
>>>>>>>
>>>>>>> out.close();
>>>>>>> urlConn.disconnect();
>>>>>>> }
>>>>>>> }
>>>>>>>
>>>>>>> ## end test client ##
>>>>>>>
>>>>>>> ## begin comet servlet ##
>>>>>>>
>>>>>>> import java.io.BufferedReader;
>>>>>>> import java.io.IOException;
>>>>>>>
>>>>>>> import javax.servlet.ServletException;
>>>>>>> import javax.servlet.http.HttpServlet;
>>>>>>> import javax.servlet.http.HttpServletRequest;
>>>>>>>
>>>>>>> import org.apache.catalina.CometEvent;
>>>>>>> import org.apache.catalina.CometProcessor;
>>>>>>>
>>>>>>> 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();
>>>>>>> // don't want timeout events
>>>>>>> cometEvent.setTimeout(1000000);
>>>>>>> if (cometEvent.getEventType() ==
>>>>>>> CometEvent.EventType.BEGIN) {
>>>>>>> log("Begin for session: " +
>>>>>>> request.getSession(true).getId());
>>>>>>> BufferedReader reader =
>>>>>>> cometEvent.getHttpServletRequest().getReader();
>>>>>>> String line = reader.readLine();
>>>>>>> if (line != null) {
>>>>>>> log("servlet received: " + line);
>>>>>>>
>>>>>>> cometEvent.getHttpServletResponse().getWriter().println("servlet
>>>>>>> received: " + line);
>>>>>>>
>>>>>>> cometEvent.getHttpServletResponse().getWriter().flush();
>>>>>>> } else {
>>>>>>> cometEvent.close();
>>>>>>> }
>>>>>>> } else if (cometEvent.getEventType() ==
>>>>>>> CometEvent.EventType.ERROR) {
>>>>>>> log("Error for session: " +
>>>>>>> request.getSession(true).getId()
>>>>>>> + ", " + cometEvent.getEventSubType());
>>>>>>> cometEvent.close();
>>>>>>> } else if (cometEvent.getEventType() ==
>>>>>>> CometEvent.EventType.END) {
>>>>>>> log("End for session: " +
>>>>>>> request.getSession(true).getId());
>>>>>>> cometEvent.close();
>>>>>>> } else if (cometEvent.getEventType() ==
>>>>>>> CometEvent.EventType.READ) {
>>>>>>> log("Read for session: " +
>>>>>>> request.getSession(true).getId());
>>>>>>> BufferedReader reader =
>>>>>>> cometEvent.getHttpServletRequest().getReader();
>>>>>>> String line = reader.readLine();
>>>>>>> if (line != null) {
>>>>>>>
>>>>>>> cometEvent.getHttpServletResponse().getWriter().println("servlet
>>>>>>> received: " + line);
>>>>>>> } else {
>>>>>>> cometEvent.close();
>>>>>>> }
>>>>>>> }
>>>>>>> }
>>>>>>> }
>>>>>>>
>>>>>>> ## end comet servlet ##
>>>>>>>
>>>>>>> ---------------------------------------------------------------------
>>>>>>>
>>>>>>> To start a new topic, e-mail: [email protected]
>>>>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>> ---------------------------------------------------------------------
>>>>>>
>>>>>> To start a new topic, e-mail: [email protected]
>>>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To start a new topic, e-mail: [email protected]
>>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>>
>>>>>
>>>>>
>>>>>
>>>> ---------------------------------------------------------------------
>>>> To start a new topic, e-mail: [email protected]
>>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>>
>>>>
>>>>
>>>>
>>> ---------------------------------------------------------------------
>>> To start a new topic, e-mail: [email protected]
>>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>>> For additional commands, e-mail: [EMAIL PROTECTED]
>>>
>>>
>>>
>>>
>>
>> ---------------------------------------------------------------------
>> To start a new topic, e-mail: [email protected]
>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>> For additional commands, e-mail: [EMAIL PROTECTED]
>>
>>
>>
>>
>
>
>
> ---------------------------------------------------------------------
> To start a new topic, e-mail: [email protected]
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
>
>
---------------------------------------------------------------------
To start a new topic, e-mail: [email protected]
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]