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
Related
I am currently using ch.ethz.ssh2.Connection to connect to my servers in java. sometimes it hangs on one server.(maybe like 10-15 seconds). I wanted to know what causes this hang time and how to avoid it.
Connection sample
conn = new ch.ethz.ssh2.Connection(serverName);
conn.connect();
boolean isAuthenticated = conn.authenticateWithPassword(user, pass);
logger.info("Connecting to " + server);
if (isAuthenticated == false) {
logger.info(server + " Please check credentials");
}
sess = conn.openSession();
// I am connecting to over 200 servers and closing them. What would be the best practice to loop thru all these servers in the minimal time.
//some servers quickly connects, while some takes some time.
why does this happen?
The main question is: Is it a code problem, a network problem or a server problem.
A code problem can be debugged - unfortunately ch.ethz.ssh2.Connection does not have any logging possibility to detect what is going inside.
May be you should thing about switching the ssh library (or use it for some tests with the problematic servers). From my experience sshj is very useful.
If it is a network problem or a server problem you can check what is going on via Wireshark. If network packets are sent but the response is delayed the problem is not the used client-side code.
My psychic debugging powers tell me that the server is doing a DNS lookup on the IP address of each client which connects. These DNS lookups are either taking a long time to complete, or they're failing entirely. The DNS lookup will block the authentication process until it finishes, successfully or not.
If the server is the OpenSSH server, this behavior is controlled by the sshd config "UseDNS" option.
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.
I want to reuse channel for multiple HTTP requests. I'm using java+netty for the server but clients could be written in C#/Java.
For the C# client I'm using HttpWebRequest with KeepAlive = true; and I don't close the channel after the arrival of the response. And it works perfect.
But when I tried the same for java <--> java communication I had some problems. I'm handling the responses from server something like in this sample and this client part.
If in if (msg instanceof LastHttpContent) { section I just do ctx.close(); I won't be able to reuse this channel again. What should I do here to be able to reuse it?
I tried:
ctx.write(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE));
or
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER);
or tried to do nothing...but when I try to reuse this channel, i have problem in this handle. The first request was handled fine, but the second gives me this error:
channelRead0: DefaultHttpResponse(decodeResult: failure(java.lang.NullPointerException), version: HTTP/1.1)
Section if (msg instanceof HttpResponse) works fine (I mean headers was read), but throws exception somewhere after that.
And:
headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
doesn't help too. To make it clear: 1st request/response is fine. Second request in same stream is fine, but there is a problem in decoding the response.
I checked Logger. 1st and second responses are equal, so I don't understand why it gets NullException when decoding it.
p.s. netty 4.0.26
You are entirely at the mercy of the clients. If they implement connection pooling, your connection will be reused. If not, not. Nothing you can do about it at the server end except observe and implement the Connection: close header if sent.
The below lines of code
HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
HttpResponse response2 = httpexecutor.execute(request2, conn, context);
log.info("Status Line "+response2.getStatusLine());
while executing the second statement my request/response is blocked by proxy. How to debug this.?
While the same statement executing from my local environment where no proxy is configured, am able to see
the log returns the below code
"Status Line HTTP/1.1 200 OK"
I think what you are looking for is to set a timeout on the request - basically telling the executor to give up if no connection can be established within a certain period of time.
This SO article covers this: Java HTTP Client Request with defined timeout
the accepted answer has important information about the fact that Apache's implementation has two timeouts - be sure to read that.
Note that it won't be possible for you to actually distinguish between a connection failure that was caused by some other problem - all you will know is that your attempt timed out. In your response to the user, you'll probably wind up saying "Unable to connect to host XXXXX. Possible causes are that your Internet connection is down, or that you have a proxy server that prevents outbound connections to that host."
We are getting a java.net.SocketTimeoutException on server B when client A connects to server B. No idea why. The client is sending data to the server and the server then throws this exception. How would one troubleshoot this issue?
Note currently this has happened only once. Not sure if this is reproduceable. Attempting to setup the test again..
I had same problems, when my users used 3G or 2G network. It means, that you send request to server, and can't estabilish connection, because of weak internet signal. You can increase timeouts on your connection
URLConnection connection;
int timeout = 30 * 1000;
connection.setConnectTimeout(timeout);
connection.setReadTimeout(timeout);
But if you have weaaak weeeaaaak internet connection, timeouts does not help you.
I'm just created 1 testFunction in WebService (or you can use one of yours) for testing connection with server before calling another required functions, and if I get SockectTimeoutException calling this function - just report to user notification "Weak internet connection!".
No data arrived at the receiver within the timeout period. That's all it means. Debugging it means finding out why the data you think was sent wasn't sent. A missing flush() for example.