HttpURLConnection inside a loop - java

I'm trying to connect to one URL that I know that exist but I don't know when.
I don't have access to this server so I can't change anything to receive a event.
The actual code is this.
URL url = new URL(urlName);
for(int j = 0 ; j< POOLING && disconnected; j++){
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int status = connection.getResponseCode();
if(status == HttpURLConnection.HTTP_OK || status == HttpURLConnection.HTTP_NOT_MODIFIED){
//Some work
}else{
//wait 3s
Thread.sleep(3000);
}
}
Java not is my best skill and I'm not sure if this code is good from the point of view of performance.
I'm opening a new connection every 3 seconds? or the connection is reused?
If I call to disconnect() I ensure that no new connections are open in the loop, but... it will impact in performance?.
Suggestions? What is the fast/best ways to know it a URL exist?

1) Do use disconnect, you don't want numerous open connections you don't use. Discarding resources you don't use is a basic practice in any language.
2) I don't know if opening and closing new network connection every 3 seconds will pollute system resources, the only way to check it is to try.
3) You may want to watch for 'ConnectException', if by "URL [does not] exist" you mean server is down.

This code is okay from a performance point of view, it will create a new connection each time. Anyway if you have a Thread.sleep(3000) in your loop, you shouldn't have to worry about performance ;)
If you're concerned about connection usage on the server side, you can look into apache HTTP client, it has a lot of features. I think it handles keep alive connections by default.

Related

Java - url.openConnection() and httpsUrlConnection.connect() is running slow when first called

I found an interesting phenomenon when writing Java programs.
I had created 3 https connections to 3 different URLs, and I found that when I call url.openConnection() and httpsUrlConnection.connect() for the FIRST time, they took nearly 300ms and 1s to execute respectively, while during the second and third call, they took nearly 0ms.
Are there any reasons for these performance difference?
BTW, is there something I can do to improve the performance?
FYI, all of the three httpsURLConnection look like this (try-catch is not shown):
Url url = new URL("https://www.google.com");
Utils.logTime(logger);
HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection();
Utils.logTime(logger);
httpsURLConnection.setRequestMethod("GET");
httpsURLConnection.setConnectTimeout(5 * 1000);
httpsURLConnection.setReadTimeout(5 * 1000);
httpsURLConnection.setRequestProperty(Utils.ACCEPT, Utils.ACCEPT_ALL);
httpsURLConnection.setRequestProperty(Utils.ACCEPT_ENCODING, Utils.GZIP);
httpsURLConnection.setRequestProperty(Utils.USER_AGENT, Utils.MOZILLA);
Utils.addCookiesToConnection(httpsURLConnection, cookieMap);
Utils.logTime(logger);
httpsURLConnection.connect();
Utils.logTime(logger);
And as you may assume, Utils and cookieMap are a class and a HashMap created by myself, so they shall not be the focus of solution.
Any ideas? Thanks in advance.
The reason for the time difference could be: the first time, socket connection needs to be established (from the source ip to the target ip and port). Once established, the same TCP connection could be reused. It's normal in network programming.
To improve efficiency and more control over the connection pooling, I would suggest considering Apache HttpClient

How to send request periodically to the client from the server by http persistent connection

I am new in http connections. The thing I want to realize is that the server should send some data (notifications) to the client periodically by persistent connection.
I wrote a code in server side by php like:
<?php
set_time_limit(0);
header('Connection: keep-alive');
$i = 0;
while($i < 10){
echo "Hello$i<br/>";
sleep(5);
$i++;
}
?>
and tried to connect to the server by java:
public static void main(String[] args) throws Exception {
URL oracle = new URL("http://localhost/connection.php");
URLConnection yc = oracle.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
I expected to get content from the server every five seconds like following:
Hello0<br/>
Hello1<br/>
...
but instead of this the java client is waiting 50 seconds. and printing:
Hello0<br/>Hello1<br/>Hello2<br/>Hello3<br/>Hello4<br/>Hello5<br/>Hello6<br/>Hello7<br/>Hello8<br/>Hello9<br/>
I want the server send notifications itself. instead of the client connect to the server every five seconds.
It's really unnecessary to add Connection: keep-alive header in response for HTTP/1.1 server, UNLESS for backward compatibility.
No matter how long or many times you sleep in that loop, it's seen as ONE request by the client nevertheless.
with that being said, your client snippet, in fact, only make ONE request to http://localhost/connection.php, and it's impossible to reuse URLConnection in order to dispatch another request(achieving persistent).
to sum up:
Persistent Connection behaviour is handled at transport layer (TCP), more specifically, you are required to reuse a client socket for multiple request to the same host plus some other requirements specified in HTTP/1.1.
Go and find some projects that are suitable for your needs, don't reinvent the wheel.
Flushing the connections seemed really good idea. But I think I found better solution. Instead of keeping connection with unlimited timeout, I think it is better to make persistent connection with 5 (N minutes) minutes timeout. It is better because when the user will be offline unexpectedly, the server will keep the connection alive anyway. and it is not good. That's why I am going to make 5 (this number is optional) connections for notification. That is the server will use first one for notification and closes the connection after sending request, and the rest 4 connections will be on duty. When the client (or java client) will receive the notification, it will make new connection to fill missing part or the connection times out.
and the client will be notified immediately every time (of course if connected to the internet).
If someone has better solution I will be happy to see that.

how to deal with 503 response code java.net

Would the following be an appropriate way of dealing with a 503 response code in java networking? What does this code- specifically the calls to disconnect and null do?
URL url = new URL(some url);
HttpURLConnection h =(HttpURLConnection)url.openConnection();
int x = h.getResponseCode();
while(x==503)
{
h.disconnect();
h = null;
h =(HttpURLConnection)url.openConnection();
x = h.getResponseCode();
}
The disconnect() closes the underlying TCP socket.
Setting the local variable to null immediately before reassigning it accomplishes nothing whatsoever.
There should be a sleep in that loop, with an interval that increases on every failure, and a limited number of retries.
Whatever you want it to do is an appropriate way. To make something failsafe, it would be better to repeat until success is achieved, rather than only handling a 503 scenario.
simplest example: loop until 200 (success) code comes back.
(better would be to abstract that out into methods and classes and use OOP and unit tests where possible.)

In Java, how close the connection and free the port/socket using HttpURLConnection?

I'm using HttpURLConnection to do download of pages in Java. I forgot to release the connections and I think this was causing some problems to my system (a webcrawler).
Now I've done some tests and see that after disconnecting, some connections still like TIME_WAIT in the results from the netstat command on Windows.
How I do to free this connection immediately?
Example code:
private HttpURLConnection connection;
boolean openConnection(String url) {
try {
URL urlDownload = new URL(url);
connection = (HttpURLConnection) urlDownload.openConnection();
connection.setInstanceFollowRedirects(true);
connection.connect();
connection.disconnect();
return true;
} catch (Exception e) {
System.out.println(e);
return false;
}
}
In some implementations, if you have called getInputStream or getOutputStream, you need to ensure that those streams are closed. Otherwise, the connection can stay open even after calling disconnect.
EDIT:
This is from the J2SE docs for HttpURLConnection [emphasis added]:
Calling the disconnect() method may close the underlying socket if a persistent connection is otherwise idle at that time.
And this is from the Android docs:
To reduce latency, this class may reuse the same underlying Socket for multiple request/response pairs. As a result, HTTP connections may be held open longer than necessary. Calls to disconnect() return the socket to a pool of connected sockets. This behavior can be disabled by setting the "http.keepAlive" system property to "false" before issuing any HTTP requests. The "http.maxConnections" property may be used to control how many idle connections to each server will be held.
I don't know what platform you are using, but it could have similar behavior.
The TME_WAIT state is imposed by TCP, not by Java. It lasts two minutes. This is normal.

BindException: address already in use on a client socket?

I've got a client-server tiered architecture with the client making RPC-like requests to the server. I'm using Tomcat to host the servlets, and the Apache HttpClient to make requests to it.
My code goes something like this:
private static final HttpConnectionManager CONN_MGR = new MultiThreadedHttpConnectionManager();
final GetMethod get = new GetMethod();
final HttpClient httpClient = new HttpClient(CONN_MGR);
get.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
get.getParams().setParameter(HttpMethodParams.USER_AGENT, USER_AGENT);
get.setQueryString(encodedParams);
int responseCode;
try {
responseCode = httpClient.executeMethod(get);
} catch (final IOException e) {
...
}
if (responseCode != 200)
throw new Exception(...);
String responseHTML;
try {
responseHTML = get.getResponseBodyAsString(100*1024*1024);
} catch (final IOException e) {
...
}
return responseHTML;
It works great in a lightly-loaded environment, but when I'm making hundreds of requests per second I start to see this -
Caused by: java.net.BindException: Address already in use
at java.net.PlainSocketImpl.socketBind(Native Method)
at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:336)
at java.net.Socket.bind(Socket.java:588)
at java.net.Socket.<init>(Socket.java:387)
at java.net.Socket.<init>(Socket.java:263)
at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:80)
at org.apache.commons.httpclient.protocol.DefaultProtocolSocketFactory.createSocket(DefaultProtocolSocketFactory.java:122)
at org.apache.commons.httpclient.HttpConnection.open(HttpConnection.java:707)
at org.apache.commons.httpclient.HttpMethodDirector.executeWithRetry(HttpMethodDirector.java:387)
at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:171)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:397)
at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:323)
Any thoughts on how to fix this? I'm guessing it's something to do with the client trying to reuse the ephemeral client ports, but why is this happening / how can I fix it?
Thanks!
A very good discussion of the problem you are running into can be found here. On the Tomcat side, by default it will use the SO_REUSEADDR option, which will allow the server to reuse sockets which are in TIME_WAIT. Additionally, the Apache http client will by default use keep-alives, and attempt to reuse connections.
Your problems seems to be caused by not calling releaseConnection on the HttpClient. This is required in order for the connection to be reused. Otherwise, the connection will remain open until garbage collector comes and closes it, or the server disconnects the keep-alive. In both cases, it won't be returned to the pool.
With hundreds of connections a second, and without knowing how long your connections keep to open, do their thing, close, and get recycled, I suspect that this is just a problem you're going to have. One thing you can do is catch the BindException in your try block, use that to do anything you need to do in the bind-unsuccessful case, and wrap the whole call in a while loop that depends on a flag indicating whether the bind succeeded. Off the top of my head:
boolean hasBound = false;
while (!hasBound) {
try {
hasBound = true;
responseCode = httpClient.executeMethod(get);
} catch (BindException e) {
// do anything you want in the bound-unsuccessful case
} catch (final IOException e) {
...
}
}
Update with question: One curious question: what are the maximum total and per-host number of connections allowed by your MultiThreadedHttpConnectionManager? In your code, that'd be:
CONN_MGR.getParams().getDefaultMaxConnectionsPerHost();
CONN_MGR.getParams().getMaxTotalConnections();
Thus, you've fired more requests than TCP/IP ports are allowed to be opened. I don't do HttpClient, so I can't go in detail about this, but in theory there are three solutions for this particular problem:
Hardware based: add another NIC (network interface card).
Software based: close connections directly after use and/or increase the connection timeout.
Platform based: increase the amount of TCP/IP ports which are allowed to be opened. May be OS-specific and/or NIC driver-specific. The absolute maximum is 65535, of which several may already be reserved/in use (e.g. port 80).
So it turns out the problem was that one of the other HttpClient instances accidentally wasn't using the MultiThreadedHttpConnectionManager I instantiated, so I effectively had no rate limiting at all. Fixing this problem fixed the exception being thrown.
Thanks for all the suggestions, though!
Even though we invoke HttpClientUtils.closeQuietly(client); but in your code in case trying to read the content from HttpResponse entity like InputStream contentStream = HttpResponse.getEntity().getContent(), then you should close the inputstream also then only HttpClient connection get closed properly.

Categories

Resources