i'm stuck with a timeout problem with DefaultHttpClient on Android. I'm trying to set the timeout with the following piece of code:
HttpClient client = new DefaultHttpClient();
HttpParams httpParameters = client.getParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, 4000);
HttpConnectionParams.setSoTimeout(httpParameters, 4000);
But if the device is connected to a network without internet connection, the timeout is never fired and the execution of http request never throws any timeout exception. I'm executing http request as follow:
HttpResponse httpResponse = client.execute(request);
I've tried also to set the timeout on the HttpRequest, with the following lines:
HttpRequestBase request = ...
request.setParams(httpParameters);
Android seems to ignore the timeout settings and when executing http request on a network with no internet connection, all the requests fails after about 20s, and not after my timeout settings.
I've also tried to close all internet connections and abort http request after a timeout with a parallel thread. I've used the following piece of code:
HttpClient client = new DefaultHttpClient();
HttpParams httpParameters = client.getParams();
HttpRequestBase request = ...
request.setParams(httpParameters);
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutReal);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutReal);
request.setParams(httpParameters);
((DefaultHttpClient) client).setParams(httpParameters);
Thread t = new Thread(){
public void run()
{
try
{
Thread.sleep(4000);
request.abort();
client.getConnectionManager().closeExpiredConnections();
client.getConnectionManager().closeIdleConnections(4000,TimeUnit.MILLISECONDS);
client.getConnectionManager().shutdown();
Log.i("TEST SHUTDOWN","SHUT DOWN ALL CONNECTIONS");
}
catch (InterruptedException e)
{
}
}
};
try
{
t.start();
HttpResponse httpResponse = client.execute(request);
}
catch (Exception e)
{
Log.i("TEST SHUTDOWN","EXCEPTION "+e);
}
finally
{
t.interrupt();
}
But even if I see from the logs that the request is aborted and the connection manager is shut down, the execution of the request is not interrupted/aborted and no exception is raised at the timeout set.
The request ends always after 20s.
Any idea why?
What you are probably seeing is that the DNS lookup is timing out. When your HTTP client attempts to make a connection, the first thing it does is try to resolve the hostname of your URL into an IP address. When doing this it doesn't take your timeout settings into account (those timeout values are only used when trying to actually make the socket connection). If you haven't got good Internet connectivity, your DNS lookup will just stall until it times out. Once that happens, your HTTP request should fail immediately with UnknownHostException.
Unfortunately you have no control over the DNS timeout, so the only way to solve your problem is to first determine if your DNS resolution is working. You should do this in a separate thread, and if you don't get successful host resolution within a few seconds, you know that your Internet connection is not reliable and you don't even have to attempt your HTTP request.
So you can try something like this:
HttpClient client = new DefaultHttpClient();
HttpParams httpParameters = client.getParams();
HttpRequestBase request = ...
request.setParams(httpParameters);
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutReal);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutReal);
request.setParams(httpParameters);
((DefaultHttpClient) client).setParams(httpParameters);
// The thread that is waiting to execute the HTTP request
final Thread waitingThread = Thread.currentThread();
Thread t = new Thread() {
boolean running = true;
public void run() {
try {
// Try to resolve the host name
InetAddress addr = InetAddress.getByName (hostname);
// Successful resolution, notify the waiting thread
if (running) {
// Signal the waiting thread that it can do the HTTP request now
waitingThread.interrupt();
}
} catch (Exception e) {
// Some problem, just ignore it
}
}
};
try {
// Start name resolution
t.start();
// Sleep for as long as we are willing to wait for the DNS resolution
Thread.sleep(4000);
// If we slept the entire time without getting interrupted, the DNS resolution took too long
// so assume we have no connectivity.
t.running = false; // We don't want to be interrupted anymore
// Don't even bother trying the HTTP request now, we've used up all the time we have
} catch (InterruptedException ie) {
// We got interrupted, so the DNS resolution must have been successful. Do the HTTP request now
HttpResponse httpResponse = client.execute(request);
}
I'm writing this code without trying it, so please forgive any typos or missing semicolons. You should get the idea.
You could try to use AndroidHttpClient instead of DefaultHttpClient. It has some specific settings for Android.
Alternatively, you could try to replace the following line:
HttpParams httpParameters = client.getParams();
with the following line
HttpParams httpParameters = new BasicHttpParams();
I don't know if this is the correct answer but, hope this helps.
The 20 seconds part of your question rfc2616 specifies 5 redirects times 4000 milis = 20 Seconds. The solution is to check for network connection before attempting network access.
// check for network connection
ConnectivityManager connMgr = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connMgr == null) {
return false; // I get a null here when there is no connection on my lg f6.
}
// check ok to process
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo == null || !networkInfo.isConnected()) {
return false;
}
return true;
Well, I had a similar problem. This is what I did to solve it.
First, I create an instance of the HttpParams:
HttpParams params = new BasicHttpParams();
Then, I don't set the settings manually. Instead I use the HttpConnectionParams class to do so. For example:
HttpConnectionParams.setStaleCheckingEnabled(params, false);
HttpConnectionParams.setConnectionTimeout(params, httpTimeout * 1000);
HttpConnectionParams.setSoTimeout(params, httpTimeout * 1000);
Then, I pass the created params when I instantiate the html client:
HttpClient client = new DefaultHttpClient(params);
I also use a Client Connection Manager, so, I pass it as the first parameter in the above call.
So, the trick is to create the HttpClient by passing already setted parameters and not chaging them afterwards.
Hope this works for you.
EDIT: Did you tried to block the redirects? HttpClientParams.setRedirecting(params, setRedirecting);
Related
I'm developing a program that sends some Logs to a database.
As logs, the main idea is to save as much information as it can, I want to avoid the part if the server where I store logs is down. What I'm trying to do is to make an http request and totally ignore server response, it doesn't matter if is online or offline. What I'm done so far is to set a timeout to my request but that doesn't resolve my problem. Here is my code:
public synchronized void LOG_sendERROR(String token, String channelnumber, String type)
{
HttpResponse response = null;
HttpParams httpParameters = new BasicHttpParams();
int timeout = 3000;
HttpConnectionParams.setConnectionTimeout(httpParameters,timeout);
int timeoutsocket = 5000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutsocket);
DefaultHttpClient httpclient = new DefaultHttpClient(httpParameters);
try
{
if (ep.getString("username", "").length() == 0)
return ;
String url = Server.Log_Server + "/LOG_CHANNEL_LOGS.aspx?params=1";
log.i("LOGS", url);
HttpGet c = new HttpGet(url);
response = httpclient.execute(c);
return ;
}
catch (Exception e)
{
e.printStackTrace();
try
{
if (response != null)
response.getEntity().consumeContent();
}
catch (Exception f)
{
}
return ;
}
}
If server is down my application stuck for 3 seconds. I want to send the logs, it doesn't matter for the client application to know whether the server saved the logs the client just send. How can I make a http request and ignore response?
After i tried many methods, the best way is to execute as a parallel task. In this way client wont ignore the response of the server but at least the application will be running normaly.
private Runnable LOG_CHANNEL_LOGS = new Runnable()
{
public void run()
{
new LOG_CHANNEL_LOGS().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
};
I need to know if my glass has internet connectivity.
I have tried to use this solution How to check if Google Glass is connected to internet using GDK
public static void isNetworkAvailable(Context context){
HttpGet httpGet = new HttpGet("http://www.google.com");
HttpParams httpParameters = new BasicHttpParams();
// Set the timeout in milliseconds until a connection is established.
// The default value is zero, that means the timeout is not used.
int timeoutConnection = 3000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
// Set the default socket timeout (SO_TIMEOUT)
// in milliseconds which is the timeout for waiting for data.
int timeoutSocket = 5000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
DefaultHttpClient httpClient = new DefaultHttpClient(httpParameters);
try{
Log.d(TAG, "Checking network connection...");
httpClient.execute(httpGet);
Log.d(TAG, "Connection OK");
return;
}
catch(ClientProtocolException e){
e.printStackTrace();
}
catch(IOException e){
e.printStackTrace();
}
Log.d(TAG, "Connection unavailable");
}
It's work ok for my in XE 17.1 but when i have updated my Glass to XE 18.1 it's work but i need to wait until TIME_OUT to know Glass have not internet connectivity. In XE 17.1 it's not happen. If i hadn't connectivity, a exception was threw without waiting TIME_OUT.
Any idea for know internet connectivity without waiting Time out?
Thanks!
Have you tried using InetAddress.getByName("google.com").isReachable(<timeout>) for testing connectivity? It might not be as reliable as a GET request over TCP, but I've seen this work pretty well in practice.
I am trying to implement ping using HttpGet but behavior is random.
I am having following code which test the internet/server connectivity:
boolean result = false;
HttpGet request = new HttpGet("www.MyServer.com");
HttpParams httpParameters = new BasicHttpParams();
HttpClient httpClient = new DefaultHttpClient(httpParameters);
try
{
HttpConnectionParams.setConnectionTimeout(httpParameters, 6000);
HttpConnectionParams.setSoTimeout(httpParameters, 6000);
HttpResponse response = httpClient.execute(request);
int status = response.getStatusLine().getStatusCode();
if (status == HttpStatus.SC_OK)
{
result = true;
}
}
catch(Exception e)
{
e.printStackTrace();
result = false;
}
Log.d("App", "Ping Result:"+result);
Above code I am running in thread as it may take time.
When I run this test for first time then I get result as true, but then after behavior is random, some times it given me error 'host unreachable' and I get result as false.
I just want to test is server is reachable from the currently configured Android network.
Is there any reliable API to test the internet/server connectivity?
UPDATE:
In a Service i have following function which initiates the test.
void startTest()
{
ServerTestThread mServerTestThread = new ServerTestThread()
mServerTestThread.start();
}
class ServerTestThread extends Thread
{
boolean result = false;
public void run()
{
//HttpGet code
//Send Message TO GUI Thread with result.
}
}
Above startTest function is creating instance of the test thread and calling start function. when test is done I am sending message to main thread which contains the result.
Thanks.
There is no problem with your code. That means either:
Sometimes server is really unreachable
Connection is slow and it time outs before server is reached.
So test setting timeout to some larger value, such as 60000(60sec), and check again. If it works, then you know it was because of timeout.
EDIT
Also please make this change, maybe it gives us more info:
Log.d("App", "Status:" + status);
if (status == HttpStatus.SC_OK)
{
result = true;
}
EDIT2
class ServerTestThread extends Thread
{
public static boolean result = false;
public static HttpGet request = new HttpGet("www.MyServer.com");
public static HttpParams httpParameters = new BasicHttpParams();
public static HttpClient httpClient = new DefaultHttpClient(httpParameters);
boolean result = false;
public void run()
{
//HttpGet code
//Send Message TO GUI Thread with result.
}
}
As a bonus,
this will tell if you if you're connected to a network.
I have the following problem:
My application needs to inform a website of a change as fast as possible
This can happen so fast that the previous webrequest hasn't been completely dealt with
The application should always send at least the last webrequest (it doesn't matter if previous ones are lost).
I'm not sure how to do this optimally. My current method is below, but gives me a warning ("Invalid use of SingleClientConnManager: connection still allocated."). I suspect I can reuse this connection, but have no clue how. Using threadSafeConnManager doesn't seem to be the solution, since I only need one connection (I think :) ).
How should I optimize my code for my needs?
The runnable in the code below is in a thread (webThread) and webrequest is a global variable that gets set to a certain url. After setting the variable, webThread.run() is fired.
private Runnable mSyncInternet = new Runnable() {
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
public void run() {
HttpGet httpGet = new HttpGet(webrequest);
try {
HttpResponse response = httpClient.execute(httpGet, localContext);
} catch (ClientProtocolException e) {
sendMessageToUI(MSG_NO_INTERNET, 1);
} catch (IOException e) {
sendMessageToUI(MSG_NO_INTERNET, 1);
}
}
};
Thanks so much in advance!
Just today I found a blog with the solution to the SingleClientConnManager issue:
public static DefaultHttpClient getThreadSafeClient() {
DefaultHttpClient client = new DefaultHttpClient();
ClientConnectionManager mgr = client.getConnectionManager();
HttpParams params = client.getParams();
client = new DefaultHttpClient(new ThreadSafeClientConnManager(params,
mgr.getSchemeRegistry()), params);
return client;
}
I tried it, and it worked perfectly!
I am currently faced to a strange problem.
I have to contact a web service, with a very long URL (there is some XML inside). The length of one of them is 943 characters.
Most of the time, the request failed with a NoHttpResponseException.
I newly added a RetryHandler, which do his job, and the request finally worked, but the execute time was 246 seconds!
I reduced the timeout, to something like 30 seconds, and occasionally, the request work.
Is there something to know about long URL to make it work better?
Or, is it just prohibited on Android?
I precise that all connection with another tinier URL (even like 200 chars) perfectly work.
Here the source code of the Http connection:
DefaultHttpClient hc = new DefaultHttpClient();
HttpProtocolParams.setUseExpectContinue(hc.getParams(), false);
HttpParams httpParameters = hc.getParams();
// Set the timeout in milliseconds until a connection is established.
int timeoutConnection = 5000;
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
// Set the default socket timeout (SO_TIMEOUT)
// in milliseconds which is the timeout for waiting for data.
int timeoutSocket = 10000;
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
hc.setParams(httpParameters);
HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
public boolean retryRequest(IOException exception, int executionCount,
HttpContext context) {
// retry a max of x times
if(executionCount >= 5){
return false;
}
if(exception instanceof NoHttpResponseException){
return true;
} else if (exception instanceof ClientProtocolException){
return true;
}
return false;
}
};
hc.setHttpRequestRetryHandler(retryHandler);
url = Tool.prepareURL(url);
Log.d(LogFilter.EXECUTE, url);
HttpGet get = new HttpGet(url);
if (eTag != null) {
get.addHeader(HEADER_IF_NONE_MATCH, eTag);
}
long time = System.currentTimeMillis();
HttpResponse rp = hc.execute(get);
Log.d(LogFilter.EXECUTE, "temps execute: "+(System.currentTimeMillis()-time));
return rp;
Thank you for your time.
I think this is a server side problem and may not respond (much) to setting the timeouts. Have you tried pasting the long url into a browser?