I am going to read from a socket in java. Here is what I am going to do:
System.out.println("Start Reading");
/* bab is socket connector */
/* and readLine is the method below.
/* public String readLine()throws IOException
{
String a = inStream.readLine();
return a;
}
*/
for( int j=0;j<9;j++)
{
response = bab.readLine();
System.out.println(response);
}
I see a lot of delay (2-3 seconds) between printing "start Reading" and first line of the response. But when I requested it with Firefox, it responsed quickly (20 ms). What is the problem? And how can I solve this problem?
I suspect the reason is the server doesn't send the line-delimiter for some time, so the readLine() method waits. I bet if you just do readByte() it must be quick.
As Firefox or any other browser wouldn't read line by line, it dosn't affect them.
Firefox is probably caching the response and is therefore able to display it very quickly to you. I suggest you clear the cache on Firefox and time it again.
If you are using a domain name for the call then Firefox will also cache the DNS lookup which could save time in Firefox whereas making the call in Java could require a DNS lookup.
If you are using Windows then download Fiddler which will allow you to monitor the HTTP connection and give you a better idea of what is happening.
Related
ive got the following code as kind of a hello world test for restlet
public static void main(String[] args) throws Exception {
//Find a way to get these from the ARGS...
Settings.setCurrent(new Settings());
// Create a new Restlet component and add a HTTP server connector to it
component.getServers().add(Protocol.HTTP, 8182);
component.getContext().getParameters().add("maxThreads", "512");
component.getContext().getParameters().add("minThreads", "100");
component.getDefaultHost().attach("/findMissingPackages", Jeblet.class);
// Now, let's start the component!
// Note that the HTTP server connector is also automatically started.
component.start();
}
#Get
public String toString() {
try {
Thread.sleep(10000);
}
catch(Exception ex) { }
String settingString = "stuff";
return settingString;
}
The problem I'm having is if I open two tabs in chrome and access the server twice in a row it takes 20 seconds to get a response on the second tab. This should take 10 seconds for both tabs.
when I debug I only have one dispatcher. how do I tell restlet that I would like more than one thread?
Opening a new browser tab (or window) is not the same as opening a new connection. Browsers are really good at re-using already open connections and the 20 seconds delay is evidence of that. You can verify this by printing out the remote IP + port in your server, it will be the same for both requests.
In Firefox you can force a new connection by pressing ctrl+F5, Chrome probably has a similar feature. But you could also write a little (multi-threaded) client program that does the get-request: it is not that difficult to write and will come in handy when you need to test/debug other features of your server.
Let me explain the problem by a scenario :
1) User visit my page "www.proxy4html.com" , fills up the form:
web-address: |www.google.co.in |
2) click submit.
3) Gets google home page with "www.proxy4html.com" in browser address bar.
Now to fetch the contents from web I am using java.net.HttpURLConnection (although to resolve this I have tried several other options too). The code works as expected if it runs stand alone
(i.e while running through public static void main(String..).. thread, it fetched whatever the html is on given web address).
But the same when runs under the Servlet environment it throws
java.net.ConnectException: Connection timed out: connect
Here is the code:
public void write(String urlString, PrintWriter writer) {
URL url;
try {
url = new URL(urlString);
HttpURLConnection huc = (HttpURLConnection) url.openConnection();
HttpURLConnection.setFollowRedirects(false);
huc.setConnectTimeout(15 * 1000 * 60);
huc.setReadTimeout(15 * 1000 * 60);
huc.setRequestMethod("GET");
huc.connect();
InputStream input = url.openStream();
logger.info("got input stream");//I never reach here in servlet env :(
int i = 0;
while((i = input.read()) != -1) {
writer.write(i);
System.out.print((char)i);
}
input.close();
} catch (ConnectException e) {
logger.log(Level.SEVERE, "", e);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
The code example given may not appear clean but point to be taken is that when the above method is invoked from Servlet passing a proper URL (and whatever outputstream), the connection is never made.
I am running all this on my tomcat which is on my local machine, which is in some corporate network (you may not want get any conclusion concerning firewall because same code is running under a p.s.v.main).
please help....
Thanks in advance.
Edit: I tried somewhat same at home and it worked fine as expected. I guess this question falls more into operation system domain rather than java. So I will like to rephrase my question again:
Is operating system (Window 7) is somehow preventing tomcat to make Http requests?
Is their any configuration under Window 7 that doesn't allow application to make Http Request other than browser?
I have seen in times that Mozilla Firefox (which I am running from a directory which is copied instead of being installed i.e may not have admin privileges and doesn't have a window registry) never able to do regular update to itself.
I understand that you prefer to insist that this is not a firewall issue (as the same code runs well as a standalone Java program), but I'm willing to take a risk here.
If you're absolutely sure that the very same code is being run in both cases (standalone case, and Tomcat case), there still is a possibility that it's a firewall issue.
The built-in firewall in Windows 7 assigns outbound rules per process per port. Is it possible that your standalone program runs with a JVM that has been allowed outbound access, whereas your Tomcat server runs with a JVM that hasn't been allowed outbound access?
In other words, are you absolutely confident that your standalone program, and your Tomcat server, are being run by the very same JVM? Very same java.exe? Under Windows, it's possible that your standalone program is actually being run by javaw.exe.
(You didn't mention whether you tried to completely disable the firewall. If you can disable the firewall completely, I'd suggest you do so, for the purpose of troubleshooting)
The application that I am working on has two parts. The server part runs on a Linux machine. The client part, an Android application, queries the server and gets necessary response. Both the parts are written in Java, use socket-based communication, and transfer textual data.
Right after sending the request, here is how the client receives the response:
public static String ReadAvailableTextFromSocket(BufferedReader input) throws IOException {
if (input.ready() == false) {
return null;
}
StringBuilder retVal = new StringBuilder();
while(input.ready()) {
char ch = (char) input.read();
retVal.append(ch);
}
return retVal.toString();
}
However, this doesn't seem to be that reliable. The input is not always ready because of server response time or transmission delays.
Looks like input.ready() is not the right way to wait for getting data.
I am wondering if there is a better way to accomplish this. Perhaps there is some standard practice that I could use.
Perhaps you should use Threads. Keep a listener thread in a while(true) loop that reads more data as it comes in, and simply buffers the data in a data structure (let's say a queue) shared with the main thread. That way, the main thread could simply dequeue data as needed. If the queue is empty, it can infer that no new data was received.
Edit: see this multithreaded chat server/client code as an example.
Here is how I solved this problem. As I am responsible for writing both, the client side as well as the server side, when a request comes to the server, the first line of information I send as the response is the number of bytes the client can expect. This way, the client first waits to read a line. Once the line is read, the client now knows how many bytes of data to expect from the server.
Hope this helps others.
Regards,Peter
I'm using URLConnection for my http client. Using Wireshark, I can see that setting up an https connection can take up to four seconds. Therefore I would like to pool connections if possible to avoid the https setup time. My flow looks like this:
public String work(String url) {
HttpURLConnection conn = (HttpURLConnection)(new URL(url)).openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String response = br.readResponseFromConnection();
conn.disconnect();
br.close();
return response;
}
public void onBtnClickTest() {
work("https://example.com/echo?param=abc");
}
With the above setup, I click my test button twice, but it looks like the https setup is done for each call, which makes me think the connection isn't really being reused (at least not in the way that I was hoping). Through Wireshark I see something like the following :
// first click
Client Hello
Server Hello
Certificate, Server Hello Done
Client Key Exchange, Change Cipher Spec, Encrypted...
Encrypted Handshake Message...
Application Data
// second click, 20 seconds after my first click.
Client Hello
Server Hello
Certificate, Server Hello Done
Client Key Exchange, Change Cipher Spec, Encrypted...
Encrypted Handshake Message...
Application Data
However, if I click the test button twice within a span of < 5 seconds, it looks like the handshake is skipped for the second run, and I immediately see the "Application Data" message. I think I remember reading somewhere that URLConnection only keeps connections pooled for 5 seconds.
So my questions:
Can URLConnection actually pool my connections in the way that I want, in that subsequent connections can skip the https handshake (if hitting the same domain)?
If the above is possible, is there a way to increase the duration that connections stay pooled? My application is unlikely to make http calls within 5 seconds of eachother.
I know HttpClient offers a pool manager to reuse a connection, but looks more complicated than URLConnection. Can it get me around # 1 & 2 if they won't do what I need?
Thank you
You can use Keep-Alive header property to persisit any httpconnection. Here is documentation on Http Keep-alive Http Keep Alive
section What can you do to help with Keep-Alive gives exact information what you are looking for. Quick search in SO gave me another link which is exactly like your question.
SO disucssion link
I'm running into an issue when i try to use the HttpClient connecting
to a url. The http connection is taking a longer time to timeout, even after i set
a connection timeoout.
int timeoutConnection = 5000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
int timeoutSocket = 5000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
It works perfect most of the time. However, every once in while, the http connection runs for ever and ignore the setconnectiontimeout, especailly when the phone is connected to wifi, and the phone was idling.
So after the phone is idling, the first time i try to connect, the http connection ignores the setconnectiontimeout and runs forever, after i cancel it and try again, it works like charm everytime. But that one time that doesn't work it creates a threadtimeout error, i tried using a different thread, it works, but i know that the thread is running for long time.
I understand that the wifi goes to sleep on idle, but i dont understand why its ignoring the setconnectiontimeout.
Anyone can help, id really appreciated.
Not sure if this helps you, however I think it's worth sharing here. While playing with the timeout stuff I found there is a third timeout type you can assign:
// the timeout until a connection is established
private static final int CONNECTION_TIMEOUT = 5000; /* 5 seconds */
// the timeout for waiting for data
private static final int SOCKET_TIMEOUT = 5000; /* 5 seconds */
// ----------- this is the one I am talking about:
// the timeout until a ManagedClientConnection is got
// from ClientConnectionRequest
private static final long MCC_TIMEOUT = 5000; /* 5 seconds */
...
HttpGet httpGet = new HttpGet(url);
setTimeouts(httpGet.getParams());
...
private static void setTimeouts(HttpParams params) {
params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT,
CONNECTION_TIMEOUT);
params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, SOCKET_TIMEOUT);
params.setLongParameter(ConnManagerPNames.TIMEOUT, MCC_TIMEOUT);
}
I've met the same problem, I guess maybe the Android doesn't support this parameter.
In my case i tested all three parameters for the ThreadSafeClientConnManager
params.setParameter( ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(20) );
params.setIntParameter( ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 200 );
params.setLongParameter( ConnManagerPNames.TIMEOUT, 10 );
ThreadSafeClientConnManager connmgr = new ThreadSafeClientConnManager( params );
The first and second worked fine, but the third didn't work as documented. No exception was thrown and the executing thread was blocked indefinitely when the DefaultHttpClient#execute() was executing.
see http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e650
"...One can ensure the connection manager does not block indefinitely in the connection request operation by setting 'http.conn-manager.timeout' to a positive value. If the connection request cannot be serviced within the given time period ConnectionPoolTimeoutException will be thrown."
Thread t=new Thread()
{
public void run()
{
try
{
Thread.sleep(absolutetimeout);
httpclient.getConnectionManager().closeExpiredConnections();
httpclient.getConnectionManager().closeIdleConnections(absolutetimeout,TimeUnit.MILLISECONDS);
httpclient.getConnectionManager().shutdown();
log.debug("We shutdown the connection manager!");
}
catch(InterruptedException e)
{}
}
};
t.start();
HttpResponse res= httpclient.execute(httpget);
t.interrupt();
Is that along the lines of what you all are suggesting?
I'm not exactly sure how to cancel the execute once it has started, but this seemed to work for me. I'm not sure which of the three lines in the thread did the magic, or if it was some combination of all of them.
You could manage the timeouts yourself, this way you can be confident that no matter what state the connection gets in, unless you receive an acceptable response, that your timeout will fire and the http request will be aborted.
I've had similar issues with timeouts on android. To resolve it what I did was used the commands to not let the phone idle while I was attempting to establish a connection and during any reads or writes to the connection. Its probably worth a shot in this case as well.
Although I haven't seen this on the Android platform, I've seen similar things on other platforms and the solution in these cases is to manage the timeout yourself. Kick off another thread (the timeout thread) when your make your request. The timeout thread counts down the requisite time. If the timeout expires before you receive any data, the timeout thread cancels the original request and you retry with a new request. Harder to code, but at least you know it will work.
From you snippet it's not ultimately clear if you set the timeouts before calling HttpClient.executeMethod(..). So this is my guess.
Well, if you idle/multitask to another application, then your thread that is running might be stopped and destroyed. Maybe you should put the connection code inside a Service instead?:
http://developer.android.com/reference/android/os/AsyncTask.html
http://developer.android.com/reference/android/app/IntentService.html
How are you making the HTTP Connection? This looks like a threading issue. If you are using a background thread, then the thread may be killed along with any timeout registered. The fact that it works the next time tells me that your code will work, if you make the call in a android component and manage the WAKE_LOCK on it yourself. Anyways please post more information about the calling mechanism?
The problem might be in the Apache HTTP Client. See HTTPCLIENT-1098.
Fixed in 4.1.2.
The timeout exception tries to reverse DNS the IP, for logging purposes. This takes an additional time until the exception is actually fired.