简体   繁体   中英

Google Cloud Endpoints on Android sometimes gives java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)

I am using Google Cloud Endpoints to create a client-server app and I am doing, for now, just the Android version. When I have my device connected to the internet via wi-fi, everything is working as it should. However, when I connect via 3G, sometimes the remote calls to the endpoints API fail with the following stacktrace:

java.net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)
at libcore.io.IoBridge.maybeThrowAfterRecvfrom(IoBridge.java:552)
at libcore.io.IoBridge.recvfrom(IoBridge.java:516)
at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:46)
at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:240)
at java.io.InputStream.read(InputStream.java:163)
at java.io.BufferedInputStream.fillbuf(BufferedInputStream.java:142)
at java.io.BufferedInputStream.read(BufferedInputStream.java:227)
at libcore.io.Streams.readAsciiLine(Streams.java:201)
at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:560)
at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:813)
at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeTunnel(HttpsURLConnectionImpl.java:493)
at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:463)
at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:442)
at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:289)
at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:239)
at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:80)
at libcore.net.http.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:165)
at com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:93)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:965)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
at com.projectbamboo.android.activity.MenuActivity$5.doInBackground(MenuActivity.java:175)
at com.projectbamboo.android.activity.MenuActivity$5.doInBackground(MenuActivity.java:1)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
at java.util.concurrent.FutureTask.run(FutureTask.java:137)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
at java.lang.Thread.run(Thread.java:856)
Caused by: libcore.io.ErrnoException: recvfrom failed: ECONNRESET (Connection reset by peer)
at libcore.io.Posix.recvfromBytes(Native Method)
at libcore.io.Posix.recvfrom(Posix.java:131)
at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:164)
at libcore.io.IoBridge.recvfrom(IoBridge.java:513)
... 30 more

Here is the code of the request that failed in this situation, but they are all called in the same way and can (and does) happen in any of them:

    final LinearLayout list = (LinearLayout) findViewById(R.id.manageGamesLayout);
    list.removeAllViews();
    AsyncTask<Void, Void, CreatedGameList> listCreated = new AsyncTask<Void, Void, CreatedGameList>() {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            refreshing--;
        }

        @Override
        protected CreatedGameList doInBackground(Void... arg) {

            Gameapi apiServiceHandle = AppConstants.getApiServiceHandle();
            GetCreatedGames function;
            try {
                function = apiServiceHandle.getCreatedGames();
                return function.execute(); // <------ line 175 is here
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(CreatedGameList gamesList) {
            refreshing++;
            List<CreatedGame> list = gamesList.getObjectsList();
            if(list == null)
                return;
            for(CreatedGame game : list){
                addCreated(game);
            }
        }
    };

    listCreated.execute();

And here is the AppConstants that is called halfway there:

private static GoogleAccountCredential _credential;

public static final JsonFactory JSON_FACTORY = new AndroidJsonFactory();

public static final HttpTransport HTTP_TRANSPORT = AndroidHttp.newCompatibleTransport();

public static Gameapi getApiServiceHandle() {
    // Use a builder to help formulate the API request.
    Gameapi.Builder helloWorld = new Gameapi.Builder(AppConstants.HTTP_TRANSPORT,
            AppConstants.JSON_FACTORY,_credential).setApplicationName("Project Bamboo");

    return helloWorld.build();
}

The device is a Samsung Galaxy S3 mini. When connected via 3G I get ~90ms ping on a normal speedtest and ~10mbit/s download, so it could be much worse.

I would like to know if there is anyway to avoid this problem, or simply how to verify if this situation ocurred to try again a few times or something like that.

Thanks for the help.

You might be performing a "Loading request"

What is a loading request? Some requests run slower because App Engine needs to create a new Java Virtual Machine (JVM) to service the request.

The quote was taken from this google page

If the server takes more time to process the request because a new instance is being started combined with the latency in your 3G network could trigger this kind of errors.

How to test?

If the error is raised, check if a new instance has been created recently, if so you might want to perform some warmup requests

You can avoid some loading requests by using warmup requests. Warmup requests load application code on a new instance before any live requests are made.

More info on warmup requests here

All the quotes were taken from this google article here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM