Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Socket send timeout #3042

Closed
sagits opened this issue Dec 14, 2016 · 18 comments
Closed

Socket send timeout #3042

sagits opened this issue Dec 14, 2016 · 18 comments

Comments

@sagits
Copy link

sagits commented Dec 14, 2016

Hi, i have created a socket connection inside a service using:

    OkHttpClient client = new OkHttpClient.Builder()
                    .readTimeout(3000,  TimeUnit.MILLISECONDS)
                    .writeTimeout(3000,  TimeUnit.MILLISECONDS)
                    .connectTimeout(3000,  TimeUnit.MILLISECONDS)
                    .build();

            Request request = new Request.Builder().addHeader(Config.WEBSOCKET_PARAM_COOKIE, "access_token=" + userToken)
                    .url(mySocketUrl)
                    .build();
            webSocket = client.newWebSocket(request, websocketListener);

Everything works fine, but now i'm trying to simulate a no connection scenario. I have turned on the airplane mode, while in a chat, and tryied to send a message using .send(String). I through that it would fire some kind of exception or the onFailure/onClosed methods, but none of them are called. How can i detect if the .send function really worked? Thanks in advance.

@swankjesse
Copy link
Collaborator

Could you provide an executable test case? Our tests show that onFailure() does get called when the network request fails.

Note that the failure isn’t synchronous. That’s not a thing websockets can do, and if you need synchronous failure you probably want to use HTTP requests instead of websockets.

@th3hamm0r
Copy link

I'm facing the same problem, as I upgraded to 3.5.0 in the hope to get working timeouts ;)

Maybe I'm wrong, but it looks like the timeouts only cover the reading of frames (I looked at 68c0211). So only the case is detected, where we've started reading a frame and reading further bytes of it time out.

What seems missing here is some kind of write timeout, which fires an exception when written bytes are not acknowledged by the other side
(Note: actually I don't know, how websockets work exactly, this is more a naive attempt to explain it. In the Chrome browser for example, you'll get a timeout after 10 secs after you called sendMessage, if the connection is dead)

@swankjesse
Copy link
Collaborator

There’s never a positive confirmation that a websocket write was accepted. You need to do that at the application layer.

Even if the TCP stack could confirm bytes were consumed by the peer, you really don’t know if they were accepted. For example, the peer might not be your application service; it might just be an HTTP proxy on the client side or a load balancer on the server side.

What you do know is that if the websocket’s onFailed() callback is called that means sent messages may not have been received.

If you need positive confirmation, use regular HTTP requests which use status codes as receipts.

@th3hamm0r
Copy link

@swankjesse Ok, I'm with you, at the end the only reliable way is to implement a health-check on the application layer.
But okhttp as a library could still provide a mechanism analog to the browser's implementations, which detects if the TCP/websocket connection is unhealthy after a message has been sent.
And on the first sight I thought this has been implemented with 3.5.0 ;)

Unfortunately I don't know how the browsers do this, but there seems to be a way to detect it.

@swankjesse
Copy link
Collaborator

We call onFailed() in this case.

@th3hamm0r
Copy link

Ah ok. If this is the case, there is either a bug or I still don't understand the implementation. Because simple tests where I've disconnected the network (eg. putting the device in airplane mode) and the client sends messages afterwards, don't lead to a onFailed() after passing the configured timeout (30s).
But I can test this again later.

@sagits
Copy link
Author

sagits commented Jan 11, 2017

Hi guys, after posting this i have read alot about websockets. As i have ready the onFailure will not be called when you try to send a message without internet, because theres no confirmation about the send status of the notification (for me onFailure was never called at all, not for other websockets libs too).

Im out of this project now (in which i needed to implement a chat), but i remember that okHttp has a ping/pong feature. The ping/pong is a websocket implematation aspect that says that when a message "ping" is received by the server it must send back a "pong" at the same time, and thats the default way to check if a webserver connection is really working (write "ping" and do a timeout if "pong" was not received soon).

@swankjesse
Copy link
Collaborator

@th3hamm0r of OkHttp doesn't detect the disconnect then that's a bug. I'll try to confirm.

@th3hamm0r
Copy link

Minor note: Sry, to use Android's air plane mode to test the issue was actually only an assumption by me. On a real phone with Android 6 a SSL websocket for example almost instantly fails with an SSLException, when I stop the WIFI or activate the air plane mode, so my assumption was wrong.

Disconnecting an intermediate node (router, hotspot) from the internet where the client "sends" messages without timeouts still works.

@swankjesse
Copy link
Collaborator

No obvious action to take on this.

@pmecho
Copy link

pmecho commented Mar 10, 2017

I've been able to reproduce this on an emulator but the device calls onFailure() as expected. No onFailure() is called when switching the emulator to airplane mode. The emulator I'm using is x86_64 with Google APIs on API 25.

@ahulyk
Copy link
Contributor

ahulyk commented Sep 20, 2017

I have reproduced that issue on OnePlus One with Android 7.1.2 - onFailure() is not called in airplane mode.

@zafrani
Copy link

zafrani commented Mar 30, 2018

We have hardware devices, each capable of allowing our app to open a web socket with it. A possible scenario we have to be able to handle is when the device we're connected to is unexpectedly powered down (maybe power outage/unplugged/etc). I've noticed that when we do unplug the device that has an open web socket with our android app, onFailure is never called.

While in this state I tested sending data from my android app to the now unpowered device, and that doesn't seem to throw any errors/callbacks either. It gets queued successfully and (I'm guessing) sent successfully (from okhttp's point of view) as the queue size never increases.

However as soon as I power up the device again onFailure is immediately called. This happens regardless of how long I wait to plug it back in. 30 seconds or 5 minutes, through out this time the app has no idea its connection is gone until the device has been powered back on.

We initialize the client similarly to the above. Because all of these connections are done over local network we have very short time outs.

OkHttpClient.Builder()
.pingInterval(2, TimeUnit.SECONDS)
.connectTimeout(2, TimeUnit.SECONDS)
.readTimeout(2, TimeUnit.SECONDS)
.writeTimeout(2, TimeUnit.SECONDS)
.build()

@swankjesse
Copy link
Collaborator

@zafrani try OkHttp 3.10.

@zafrani
Copy link

zafrani commented Apr 2, 2018

Thank you, updating fixed this problem.

@Witype
Copy link

Witype commented May 31, 2018

there are some question for me in okhttp 3.10.0,

        OkHttpClient okHttpClient =
                new OkHttpClient.Builder()
                        .connectTimeout(SOCKET_CONNECT_TIMEOUT, TimeUnit.SECONDS)
                       .pingInterval(30,TimeUnit.SECONDS)
                        .readTimeout(SOCKET_READ_TIMEOUT, TimeUnit.SECONDS)
                        .writeTimeout(SOCKET_WRITE_TIMEOUT,TimeUnit.SECONDS)
                        .retryOnConnectionFailure(false)
                        .build();

the network limit at 1kb upload,
when I use code

mWebSocket.send("some thing");

the server not Received anything after SOCKET_WRITE_TIMEOUT,the client not call onFailure also,
How can I fix it

@swankjesse
Copy link
Collaborator

@Witype please open a new issue with an executable test case that demonstrates the problem. There are lots of test cases in the test suite to get you started.

@john-lanticse
Copy link

Got stuck on this for awhile. Turns out some Emulator seems to have a problem with onFailure method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants