Building42 / Telegraph

Secure Web Server for iOS, tvOS and macOS

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

WebSocket can't connect after moving to background a while and go back

donly opened this issue · comments

commented

Hello.
I like this great project, and it help me a lot.
I have a problem like #50 said:

after a while (i.e 10 minutes) leaving the server on (an iPad) with a socket connection open (by calling server.start(onPort:), the other devices cannot connect the server anymore.

And I run the server using these code, and invoke it every time moving to the foreground, but it doesn't work:

...
    // Create the server instance
    
    if server == nil {
      if let identity = identity, let caCertificate = caCertificate {
        server = Server(identity: identity, caCertificates: [caCertificate])
      } else {
        server = Server()
      }
    }
    
    if server.isRunning { return }  // after moving to background a while and go back, it will return here. 
    // Set the delegates and a low web socket ping interval to demonstrate ping-pong
    server.delegate = self
    server.webSocketDelegate = self
    server.webSocketConfig.pingInterval = 10
    server.concurrency = 4

    // Start the server on localhost
    // Note: we'll skip error handling in the demo
    try! server.start(port: 9000)
    // Log the url for easy access
    log.debug("[SERVER] Server is running - url: \(serverURL())")
...

After moving to background a while and go back, it will return here.
if server.isRunning { return }

And the WebSocket client can't connect it anymore:

const socket = new WebSocket('ws://[Telegraph webserver host IP]:9000');

it shows the error:

WebSocket network error: The operation couldn’t be completed. Connection refused

What's wrong with there, is there a best practice for resume the server without stop and restart?

Hi donly,

Unfortunately I think you are running into the issue that Apple is closing your network connections. Unless your app is a music app or other app that has special permissions to keep connections open while suspended, Apple is going to clean up most of your app after it is has been in the background for a while. Apple does this to save memory and battery life and other programs might need that extra bit of performance to run.

See also this section of the readme:
https://github.com/Building42/Telegraph#what-if-the-device-goes-on-standby

It tells you that you can request a bit of extra time, but unfortunately after that your connections will be closed.

If your app is a music app, I believe you can use the Background Audio entitlement to keep it alive:
https://developer.apple.com/documentation/avfoundation/media_playback_and_selection/creating_a_basic_video_player_ios_and_tvos/enabling_background_audio

Please let me know if you have any further questions.

commented

Yes, you are right, that is the reason why it will lose the connection. my point is how to resume the connection.

To workaround this I would do the following:

Server side

  • Add the background task to try to get as much time from the OS as you can
  • When your time is almost up, stop the (Telegraph) server
  • When your app resumes, start the server

Client side
On the client side you want the WebSocket client to try to restore the connection whenever you can. If the client gets disconnected, you could try to reconnect in 5 seconds. If 5 seconds is too often, you can always start at 5 sec. and then whenever it fails to connect increase the interval a bit and retry (e.g. start with 5sec., then retry after 30sec., then after 1min., then after 5min, it depends on your requirements).

Bonjour
Another thing that could help you, is to publish a Bonjour NetService after you start your server. Clients can use a Bonjour NetServiceBrowser to detect the service on your network and use it as a signal that your server is ready to accept connections (note: this solution probably only makes sense in a LAN).

Bonjour can also tell you when a service is no longer available, however I advice against disconnecting a client based on this information. Your client will usually disconnect automatically when the server is no longer available. It can be a great addition to the poll-every-x-sec-strategy that I describe above. Let's say your client has been trying to connect for a while and is at the 5min. poll interval. With a long poll interval like that, it could take up to 5min. between the server starting and the client trying to reconnect. When you add Bonjour to the mix, you could try to connect immediately when you detect that the server published a Bonjour service.

commented

Thank you for the very details of suggestions.

The last question, after background task time is almost up and resumes the app, it will return here.

if server.isRunning { return }

Actually the server has stopped. is this a bug?

That could be a bug. I believe it is looking at the port status of the listener to determine if it is running. If the server wasn't stopped gracefully that could incorrectly report that it is still running.

I'll keep this open so that I can do a few tests on that later.

If the server wasn't stopped gracefully that could incorrectly report that it is still running.

This is still happening. Are you tracking this issue on a different ticket?

Just ran into the same issue. I expected isRunning to be false when the server goes offline for some reason. The bug almost made it to production.