I am trying to access a remote service via Volley and I end up in the on error response function
with the error:
02-26 10:29:53.491: D/MyApp(1592): java.net.SocketTimeoutException: failed to connect to 10.10.201.10 (port 443) after 5000ms
I can access this IP from my browser and I can see the interface fine.
Why do I get this from eclipse/volley? How can I debug this?
Did you set socket timeout value as 5000ms? If so, the request is failing since it is taking more than 5000ms. Try increasing the time out value in your custom Request class
public static final int MY_SOCKET_TIMEOUT_MS = 30000;
#Override
public Request<?> setRetryPolicy(RetryPolicy retryPolicy) {
retryPolicy = new DefaultRetryPolicy(MY_SOCKET_TIMEOUT_MS,
DefaultRetryPolicy.DEFAULT_MAX_RETRIES , DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
return super.setRetryPolicy(retryPolicy);
}
What is the response time when you access it from browser? Is it shorter that that it takes in Eclipse?
If you know the average response time, you can increase timeout duration in Eclipse. Whatever library you use, there must be some method like setTimeout(int millis). There are not further things you can do unless you dig into the service codes.
Does your server return any kind of data, SocketTimeoutException occurr when there are blocking issues in read() or accept(), ie. if server doesn't return any data in defined timeout interval this exception will rise. It also could be a network problem, delay of some kind.
Related
I seem to be having a small problem with MulticastSocket on Android: writing an SSDP-related application. The socket works just fine when I set everything up the first time, but when I stop discovery, and try to restart things, I just get a SocketException: Socket Closed. I'm not closing the socket, I'm simply stopping the Kotlin Coroutine that is responsible for calling socket.receive() in a loop. Example:
fun listenForPackets(): Flow<DatagramPacket> {
return flow {
multicastSocket.use {
val incomingBuffer = ByteArray(MULTICAST_DATAGRAM_SIZE)
while (true) {
val incomingPacket = DatagramPacket(incomingBuffer, incomingBuffer.size)
it.receive(incomingPacket)
emit(incomingPacket)
incomingPacket.length = incomingBuffer.size
}
}
}
}
The problem
So the problem is that when I try to call that function again, I get a SocketException: Socket Closed. The socket initialization code is run once, meaning that toggling discovery on/off will use the same socket multiple times; the following code is run once throughout the whole application:
multicastSocket = MulticastSocket(MULTICAST_PORT)
multicastSocket.reuseAddress = true
multicastSocket.joinGroup(multicastGroup)
multicastLock.acquire()
What I have tried
My first thought was that I was not cancelling the Kotlin Coroutine correctly. As a result, I switched to using typical Java Threads, to no avail. Starting the thread the first time works, but, restarting discovery yields the same problem. I have also tried to not leave the group, and keep the multicastLock acquired - same problem.
What works
What works is having the initialization code (where I assign the socket, join the group, and acquire lock) run every time I need to start a scan. At the end of the scan, I reset all of the variables (leave group, release lock, close socket). So my question becomes - is this the correct approach? Or am I simply doing something else wrong?
Just to re-iterate, I'm discovering packets just fine, the issue is with restarting the discovery. Thank you in advance for any help!
private boolean isRecoverable(IOException e, boolean requestSendStarted) {
....
// If there was an interruption don't recover, but if there was a
//timeout connecting to a route
// we should try the next route (if there is one).
if (e instanceof InterruptedIOException) {
return e instanceof SocketTimeoutException && !requestSendStarted;
}
....
return true;
}
Here is the code snippet in RetryAndFollowUpInterceptor in OKHttp.
My question is why OkHttp not retry when SocketTimeoutException and requestSendStarted == true?
Because I think if there are some other routers, we can retry another ip or router
Consider the case where a request was successfully sent and the problem occurred when response data was transmitted to the client. Automatic retry in this case may make the server to repeat some action (increasing some count, writing a record somewhere) which may be undesirable. OKHttp lets the user to decide what to do in this case.
The goal was to retry if OkHttp couldn’t connect at all. If the server was reachable, but just responded slowly, then it’s just as likely to be an application-layer problem where retrying won’t help.
I'm trying to figure out specifically how much of my app's data use is being used by the requests I send with OkHttpClient, and I saw that I can use TrafficStats to tag a thread and then see it's network activity with the tag.
if I do something like
TrafficStats.setThreadStatsTag(1234);
okHttpClient.execute(request);
then it actually tags it okay(ish), but then when I use the async method (okHttpClient.enqueue(request)) it doesn't (which is kinda obvious though I hoped they'd have support for that).
So I tried a couple of things:
Setting a dispatcher for the client where it's a normal dispatcher which basically on every execute replaces the Runnable it receives with a new runnable that first tags the thread an then runs the original runnable - some traffic was tagged but a lot wasn't.
Setting a socket factory which basically tags every socket it produces - still some some traffic tagged but most of it wasn't.
Any ideas?
I think TrafficStats.setThreadStatsTag() is for thread, so maybe we can add an interceptor for okhttp client.
private static class TrafficStatInterceptor implements Interceptor {
int mTrafficTag;
TrafficStatInterceptor(int trafficTag) {
mTrafficTag = trafficTag;
}
#Override
public Response intercept(Chain chain) throws IOException {
if (mTrafficTag > 0) {
TrafficStatUtils.setThreadStatsTag(mTrafficTag);
} else {
Log.w(TAG, "invalid traffic tag " + mTrafficTag);
}
return chain.proceed(chain.request());
}
}
then just add this interceptor
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.addNetworkInterceptor(new TrafficStatInterceptor(trafficTag));
It’s difficult to do generally because with HTTP/2 sockets are shared across requests. With HTTP/1.1 they’re reused. Your best bet will be to write a network interceptor to tag the current thread. That’ll handle all HTTP/1.1 traffic and outgoing HTTP/2 traffic. There’s currently no API to access the thread that reads incoming HTTP/2 traffic.
If an Android Volley post request fails due to network loss, will Android Volley retry the post after the network connection is restored automatically? Will it fire all of the request attempts, wait for connection to be reestablished or simply trigger an error and stop?
If Android Volley doesn't retry after a connection is reestablished, it seems I will have to create logic so that I have an extra queue for whenever the connection gets lost, and that will retry whenever connection state changes.
As per this link:
There is no direct way to specify request timeout value in Volley, but there is a workaround, you need to set a RetryPolicy on the request object. The DefaultRetryPolicy class takes an argument called initialTimeout, this can be used to specify a request timeout, make sure the maximum retry count is 1 so that volley does not retry the request after the timeout has been exceeded.
Setting Request Timeout:
request.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 1, 1.0f));
If you want to retry failed requests (due to timeout) you can specify that too using the code above, just increase the retry count. Note the last argument, it allows you to specify a backoff multiplier which can be used to implement “exponential backoff” that some RESTful services recommend.
The link has a lot of useful tips and tricks for using Volley. Hope this helps!
If an Android Volley post request fails due to network loss, will Android Volley retry the post after the network connection is restored automatically?
No, it won't. I might not even be desired depending on your application.
Will it fire all of the request attempts, wait for connection to
reestablish or simply trigger an error and stop?
It simply throws an error. And yes, you should write this kind of logic yourself.
In case an IOException appears (e.g. java.net.ConnectException), Volley does not use the retry policy.
Volley uses only the retry policy in case of SocketTimeoutException, ConnectTimeoutException or if the HTTP response code is 401 (forbidden) or 302 (moved permanently).
if you use (AsyncHttpClient) you can try call this methode :
setMaxRetriesAndTimeout(int retries, int timeout)
Sets the maximum number of retries and timeout for a particular Request.
*
* #param retries maximum number of retries per request
* #param timeout sleep between retries in milliseconds
*/
I have this problem since I try to volley request on a method and onErrorResponse method of volley call that method again.example:
#Override
public void onErrorResponse(VolleyError volleyError) {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
sendOTPAgain();//this method call again and again
}
}, 1000);
}
How can I check whether Volley gets the results of a JsonObjectRequest from the cache or from the network?
I need to show a progress dialog when it needs a network connection but not when the results are quickly received from the cache.
my request looks something like this
volleyQueue = Volley.newRequestQueue(this);
JsonObjectRequest jr = new JsonObjectRequest(Request.Method.POST, url, null, new Response.Listener<JSONObject>(){...stuff}, new Response.ErrorListener(){...errorstuff});
jr.setShouldCache(true);
volleyQueue.add(jr);
I did this by overriding Request#addMarker and checking for a "cache-hit" marker being added:
public class MyRequest<T> extends Request<T> {
protected boolean cacheHit;
#Override
public void addMarker(String tag) {
super.addMarker(tag);
cacheHit = false;
if (tag.equals("cache-hit")){
cacheHit = true;
}
}
}
Before making the Request you can get the cache from the Request Queue and check if the Entry is not null.
mRequestQueue.getCache().get("key");
The key for each request is usually the URL.
I guess you should have to check if the Entry has expired too.
Volley has a built in way to know if image requests are immediate through the ImageContainer class, but it doesn't seem to have a similar mechanism for other requests such a JSON object request.
It seems that you have 2 main choices:
You can set a timer for something like 300ms after you request the JSON (test for the best time). When the timer is done, check to see if you have the result already, otherwise show the dialog. I know this is a bit of a "hack" but it could be good enough.
Edit the Volley code to add an "isImmediate" flag to every request. There are multiple ways to achieve this. I suggest starting at CacheDispatcher
Starting from Tim Kelly's answer.
by the time you check "cacheHit", it'll be reverted to false and you'll not know that it's a cache hit because many other tags are received after "cacheHit" is received and before the "onResponse" is called.
So, add
if(tag.equals("network-http-complete")){
cacheHit = false;
}
and remove cacheHit = false;
adb shell setprop log.tag.Volley VERBOSE
Run this command in your terminal, you may need to set 'adb' in your path in order to use that command, it should be located in your sdk/platform-tools/ dir.
This will provide much more detailed volley logs and will show something along the lines of an execution stack for a volley request which exhibits cache hits or misses.