|
Quick Lists
|
|
Bug ID:
|
4314224
|
|
Votes
|
0
|
|
Synopsis
|
NT buffers *input* over URL connection
|
|
Category
|
java:classes_net
|
|
Reported Against
|
kestrel-rc1
|
|
Release Fixed
|
|
|
State
|
11-Closed, duplicate of 4333920,
bug
|
|
Priority:
|
3-Medium
|
|
Related Bugs
|
4333920
|
|
Submit Date
|
20-FEB-2000
|
|
Description
|
2/6/2000 xxxxx@xxxxx -- even with a 1.2.2 client, the messages arrive all at once. Is this just a matter of flushing a buffer at the servlet end?
(please see Comments section)
java version "1.3.0rc1"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0rc1-T)
Java HotSpot(TM) Client VM (build 1.3.0rc1-S, mixed mode)
This might be a java.io issue.
My app sends a request to a servlet, the servlet responds every few seconds
with a status message, and then sends the replay. On 1.2.2 everything was
fine, but in 1.3 the whole output, including status messages, appears at once.
The following example has two parts, a server part and a client part. The
server part is a servlet for JSDK2.0. I run it on customer , however, these seems
irrelevant since it works on all 1.2.2 clients.
The servlets sends 10 short message every two seconds after the connection has
been established.
The client piece (after the obvious adjustments) will contact the server and
should reads the messages when they are sent. Instead, all messages are read
on once.
I have not done extensive impact studies yet, but my guess is that on
transactions that task a long time, the client will timeout.
Servlet code
============
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public final class TestServlet extends HttpServlet {
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
public void doPost (HttpServletRequest request, HttpServletResponse
response) throws ServletException {
try {
response.setContentType("text/html");
InputStream is = request.getInputStream();
byte[] buffer = new byte[5];
is.read(buffer);
System.out.println(new String(buffer));
OutputStream os = response.getOutputStream();
for (int i = 0; i < 10; i++) {
String text = "Test " + i;
os.write(text.getBytes());
os.flush();
Thread.sleep(2000);
}
is.close();
os.close();
}
catch (Exception e) {
e.printStackTrace(System.out);
}
}
}
client code
===========
import javax.swing.*;
import java.net.*;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
public final class ConnectDelay extends JFrame {
JTextField field = new JTextField(20);
JPanel panel;
public static void main(String argv[]) {
ConnectDelay app = new ConnectDelay();
}
public ConnectDelay() {
super("Connection Test");
panel = new JPanel();
panel.add(new JLabel("Message:"));
panel.add(field);
getContentPane().add(panel);
pack();
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
show();
runTest();
}
public void runTest() {
try {
byte[] buffer = new byte[6];
URL url = new URL
("http://idgiot.dev.donnell.com/servlets/TestServlet");
HttpURLConnection connection = (HttpURLConnection)
url.openConnection();
connection.setUseCaches(false);
connection.setRequestMethod("POST");
connection.setAllowUserInteraction(true);
connection.setDoOutput(true);
OutputStream os = connection.getOutputStream();
os.write("Hello".getBytes());
os.close();
InputStream is = connection.getInputStream();
int length = is.read(buffer);
while (length != -1) {
String text = new String(buffer);
field.setText(text);
System.out.println(text);
Rectangle rect = field.getBounds();
panel.paintImmediately
(rect.x,rect.y,rect.width,rect.height);
length = is.read(buffer,0,6);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
}
-----------------------
(Review ID: 100647)
======================================================================
|
|
Work Around
|
N/A
|
|
Evaluation
|
Using the given test case, tomcat server on NT 4.0 server JRE 1.3RC1-T the buffering behaviour seems perfectly normal. I tried this with W98/WNT and Solaris clients.
I suspect some other variable outside of the JRE is causing the problem.
xxxxx@xxxxx 2000-02-29
As stated the customer is still experiencing this problem. Since we have been unable to reproduce this problem I suggest the customer try to narrow the focus to just the JRE. In other words would it be possible to create a test without the servlet code?
xxxxx@xxxxx 2000-03-29
xxxxx@xxxxx 2000-07-18
To clarify my previos statement "the buffering behaviour seems perfectly normal" I did not mean to imply that there should be buffering but rather the lack of buffering is the expected behavior.
According to the most recent comments there is a work around available by configuring Apache to use HTTP1.0 when communicating with a Java client.
This fact suggests that there is some strange interaction between Apache or the HttpServlet class and not necessarily the Java runtime. J2SE v1.3 supports
HTTP 1.1 which may explain why the customer saw a change when moving from 1.2.2 to 1.3. In HTTP 1.1 there is support for the "chunked" transfer encoding which Apache may be using. There is a an article on the Apache web site describe a similar problem which is available at
http://www.apache.org/docs-1.2/misc/known_client_problems.html
which is where I suspect the customer found the work around. If the customer can
verify "chunked" encoding is in use then we may be able to reproduce the problem. To prove that the problem does not exist in the absence of Apache or the Servlet classes I have modified the customer test to operate completely stand alone. The server source is attached (the client was unchanged).
Please have the customer verify the test as well as whether chunked encoding is in use. If chunked encoding is in use I would be interested in see the snoop trace.
//=============== Servlet.java sans HttpServlet
import java.io.*;
import java.net.*;
import java.io.*;
import java.util.*;
public final class Servlet implements Runnable {
private Socket client;
private int id;
public Servlet (Socket client, int id) {
this.client = client;
this.id = id;
}
//
// APPLICATION ENTRY POINT:
//
public static void main(String[] args) {
int port = 8080;
int errCount = 0;
if (args.length == 1) {
try {
port = Integer.parseInt(args[0]);
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
System.exit(1);
}
}
ServerSocket ss = null;
try {
ss = new ServerSocket(port);
ThreadGroup group = new ThreadGroup("Servlet");
Thread t = new Thread(group, new Servlet(ss.accept(), 1));
t.start();
//
// If we aren't looping forever, then we need to wait for the
// threads to finish.
//
while (group.activeCount() > 0) {
try {
Thread.sleep(15000); // wait for 15 seconds
} catch (InterruptedException e) {
// ignore timer exception
}
}
} catch (BindException be) {
be.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (ss != null) ss.close();
} catch (IOException e) {
// ignore close exception
}
}
}
//
// THREAD ENTRY POINT:
//
public void run() {
doClient();
}
//
// METHOD(S):
//
//
// Do the client's work.
//
private void doClient() {
try {
InputStream is = client.getInputStream();
byte[] buffer = new byte[5];
is.read(buffer);
System.out.println(new String(buffer));
PrintStream os = new PrintStream(client.getOutputStream());
sendHttpResponse("HTTP/1.1", 200, null, 0, os); // ct ignored
for (int i = 0; i < 10; i++) {
String text = "Test " + i;
os.write(text.getBytes());
os.flush();
Thread.sleep(2000);
}
is.close();
os.close();
} catch (Exception e) {
e.printStackTrace(System.out);
}
}
//
// Send an HTTP response to the client.
//
private void sendHttpResponse(String version, int httpCode, String ct,
int length, PrintStream out) {
// not HTTP/0.9 request
if (version != null && version.startsWith("HTTP/")) {
out.print(version + " " + httpCode);
switch (httpCode) {
case HttpURLConnection.HTTP_NOT_FOUND:
out.print(" Not Found");
break;
case HttpURLConnection.HTTP_NOT_IMPLEMENTED:
out.print(" Not Implemented");
break;
case HttpURLConnection.HTTP_OK:
out.print(" OK");
break;
}
//
// While assembling the HTTP header line, we use print()
// instead of println() because we need to generate the
// specific <CR><NL> sequences. println() will generate
// <NL> on Unix and <CR><NL> on Win* so if we include <CR>
// in a println() call we are okay on Unix and wrong on
// Win*.
//
out.print("\r\n");
Date now = new Date();
out.print("Date: " + now + "\r\n");
out.print("Server: " + "Servlet" + " 1.0\r\n");
if (ct == null) {
out.print("Content-type: text/html\r\n");
} else {
//out.print("Content-length: " + length + "\r\n");
out.print("Content-type: " + ct + "\r\n");
}
out.print("\r\n");
}
String bodyHead = "<BODY><H1>HTTP Error ";
String bodyTail = "</H1></BODY><HTML>";
String headerHead = "<HTML><HEAD><TITLE>";
String headerTail = "</TITLE></HEAD>";
switch (httpCode) {
case HttpURLConnection.HTTP_NOT_FOUND:
out.println(headerHead + "File Not Found" + headerTail);
out.println(bodyHead + httpCode + ": Not Found" + bodyTail);
break;
case HttpURLConnection.HTTP_NOT_IMPLEMENTED:
out.println(headerHead + "Not Implemented" + headerTail);
out.println(bodyHead + httpCode + ": Not Implemented"
+ bodyTail);
break;
case HttpURLConnection.HTTP_OK: // nothing more to send
break;
}
}
}
//===============
On examination the issue is that Apache/Tomcat is buffering the 10 "Test x" messages
and when the HttpServletResponse output stream is closed it sends a single chunk
(60 bytes) to the http client -- ie: out.flush is not flushing the output to the
http client in a chunk.
However 1.3 is not without fault becuase it must read all chunks before it returns
the input stream to the application. This isn't the cause of the buffering issue
with this test case but it is something that must also be examined.
xxxxx@xxxxx 2000-09-20
|
|
Comments
|
PLEASE NOTE: JDK6 is formerly known as Project Mustang
|
|
|
 |