mirror of https://github.com/grpc/grpc.git
parent
f613be8e82
commit
965a015b05
2 changed files with 86 additions and 53 deletions
@ -1,53 +0,0 @@ |
|||||||
|
|
||||||
# gRPC iOS Network Transition Behaviors |
|
||||||
On iOS devices, network transitions happen frequently. A device may have |
|
||||||
multiple interfaces to connect to network, and these interfaces may become |
|
||||||
broken or alive at any time. This document describes how these network changes |
|
||||||
should be handled by gRPC and current issues related. |
|
||||||
|
|
||||||
## gRPC iOS with TCP Sockets |
|
||||||
### Model |
|
||||||
We classify network connectivity of the device at a given time in three |
|
||||||
categories: WiFi, cellular, and none. The network connectivity information is |
|
||||||
obtained from `SCNetworkReachability` API and the category is determined by |
|
||||||
`SCNetworkReachabilityFlags` as follows: |
|
||||||
|
|
||||||
| Reachable | ConnectionRequired | IsWAAN | **Category** | |
|
||||||
|:---------:|:------------------:|:------:|:------------:| |
|
||||||
| 0 | X | X | None | |
|
||||||
| X | 1 | X | None | |
|
||||||
| 1 | 0 | 0 | WiFi | |
|
||||||
| 1 | 0 | 1 | Cellular | |
|
||||||
|
|
||||||
Whenever there is a transition of network between these three categories, the |
|
||||||
previous channels is assumed to be broken. If there is an unfinished call, the |
|
||||||
call should return with status code `UNAVAILABLE`. All active gRPC channels |
|
||||||
will be destroyed so that any new call will trigger creation of new channel |
|
||||||
over new interface. In addition to that, when a TCP connection breaks, the |
|
||||||
corresponding channel should also be destroyed and calls be canceled with |
|
||||||
status code `UNAVAILABLE`. |
|
||||||
|
|
||||||
### Known issues |
|
||||||
There are several issues related to BSD sockets known to us that causes |
|
||||||
problems. |
|
||||||
|
|
||||||
* TCP socket stalls but does not return error when network status transits from |
|
||||||
Cellular to WiFi. This problem is workarounded by |
|
||||||
[ConnectivityMonitor](https://github.com/grpc/grpc/blob/master/src/objective-c/GRPCClient/private/GRPCConnectivityMonitor.m). |
|
||||||
* TCP socket stalls but does not return error when WiFi reconnects to another |
|
||||||
hotspot while the app is in background. |
|
||||||
|
|
||||||
If you encounter these problems, the best solution is to switch to CFStream |
|
||||||
implementation which eliminates all of them. |
|
||||||
|
|
||||||
## gRPC iOS with CFStream |
|
||||||
gRPC iOS with CFStream implementation uses Apple's networking API to make |
|
||||||
connections. It resolves the issues above that is known to TCP sockets on iOS. |
|
||||||
Users are recommended to use this implementation rather than TCP socket |
|
||||||
implementation. With CFStream implementation, a channel is broken when the |
|
||||||
underlying stream detects an error or becomes closed. The behavior of streams |
|
||||||
in CFStream are not documented by Apple, but our experiments show that it is |
|
||||||
very similar to the model above, i.e. the streams error out when there is a |
|
||||||
network connetivity change. So users should expect channels to break when the |
|
||||||
network transits to another state and pending calls on those channels return |
|
||||||
with status code `UNAVAILABLE`. |
|
@ -0,0 +1,86 @@ |
|||||||
|
|
||||||
|
# gRPC iOS Network Transition Behaviors |
||||||
|
Network connectivity on an iOS device may transition between cellular, WIFI, or |
||||||
|
no network connectivity. This document describes how these network changes |
||||||
|
should be handled by gRPC and current known issues. |
||||||
|
|
||||||
|
## Expected Network Transition Behaviors |
||||||
|
The expected gRPC iOS channel and network transition behaviors are: |
||||||
|
* Channel connection to a particular host is established at the time of |
||||||
|
starting the first call to the channel and remains connected for future calls |
||||||
|
to the same host. |
||||||
|
* If the underlying connection to the remote host is broken, the channel is |
||||||
|
disconnected and enters TRANSIENT\_FAILURE state. |
||||||
|
* A channel is broken if the channel connection is no longer viable. This |
||||||
|
happens when |
||||||
|
* The network interface is no longer available, e.g. WiFi or cellular |
||||||
|
interface is turned off or goes offline, airplane mode turned on, etc; |
||||||
|
* The underlying TCP connection is no longer valid, e.g. WiFi connects to another hotspot, cellular data switched from LTE to 4G, etc; |
||||||
|
* A network interface more preferable by the OS is valid, e.g. WiFi gets connected when the channel connects via cellular. |
||||||
|
* A channel in TRANSIENT\_FAILURE state attempts reconnection on start of the |
||||||
|
next call to the same host, but only after a certain backoff period (see |
||||||
|
corresponding |
||||||
|
[doc](https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md)). |
||||||
|
During the backoff period, any call to the same host will wait until the |
||||||
|
first of the following events occur: |
||||||
|
* Connection succeeded; calls will be made using this channel; |
||||||
|
* Conncetion failed; calls will be failed and return UNAVAILABLE status code; |
||||||
|
* The call's deadline is reached; the call will fail and return |
||||||
|
DEADLINE\_EXCEEDED status code. |
||||||
|
|
||||||
|
## Implementations |
||||||
|
### gRPC iOS with TCP Sockets |
||||||
|
gRPC's default implementation is to use TCP sockets for networking. It turns |
||||||
|
out that although Apple supports this type of usage, it is [not recommended by |
||||||
|
Apple](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/SocketsAndStreams/SocketsAndStreams.html) |
||||||
|
and is also flawed. |
||||||
|
|
||||||
|
#### TCP Sockets Issues |
||||||
|
The TCP sockets on iOS is flawed in that it does not reflect the viability of |
||||||
|
the channel connection. Particularly, we found the following issues related to |
||||||
|
TCP sockets: |
||||||
|
* When a TCP sockets connection is established on cellular data and WiFi |
||||||
|
becomes available, the TCP socket neither return an error event nor continue |
||||||
|
sending/receiving data on it, but still accepts write on it. |
||||||
|
* The TCP sockets does not report certain events that happens in the |
||||||
|
background. When a TCP connection breaks in the background for the reason |
||||||
|
like WiFi connects to another hotspot, the socket neither return an error nor |
||||||
|
continue sending/receiving data on it, but still accepts write on it. |
||||||
|
|
||||||
|
#### gRPC iOS resolutions |
||||||
|
We introduced |
||||||
|
[`ConnectivityMonitor`](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/SocketsAndStreams/SocketsAndStreams.html) |
||||||
|
in gRPC iOS library to alleviate these issues in TCP sockets, which changes the |
||||||
|
network transition behaviors a bit. |
||||||
|
|
||||||
|
We classfy network connectivity state of the device into three categories based |
||||||
|
on flags obtained from `SCNetworkReachability` API: |
||||||
|
|
||||||
|
| Reachable | ConnectionRequired | IsWWAN | **Category** | |
||||||
|
|:---------:|:------------------:|:------:|:------------:| |
||||||
|
| 0 | X | X | None | |
||||||
|
| X | 1 | X | None | |
||||||
|
| 1 | 0 | 0 | WiFi | |
||||||
|
| 1 | 0 | 1 | Cellular | |
||||||
|
|
||||||
|
Whenever there is a transition of network between two of these categories, all |
||||||
|
previously existing channels are assumed to be broken and are actively |
||||||
|
destroyed. If there is an unfinished call, the call should return with status |
||||||
|
code `UNAVAILABLE`. |
||||||
|
|
||||||
|
`ConnectivityMonitor` is able to detect the scenario of the first issue above |
||||||
|
and actively destroy the channels. However, the second issue is not resolvable. |
||||||
|
To solve that issue the best solution is to switch to CFStream implementation |
||||||
|
which eliminates all of them. |
||||||
|
|
||||||
|
### gRPC iOS with CFStream |
||||||
|
gRPC iOS with CFStream implementation uses Apple's networking API to make |
||||||
|
connections. It resolves the issues above that is known to TCP sockets on iOS. |
||||||
|
Users are recommended to use this implementation rather than TCP socket |
||||||
|
implementation. The detailed behavior of streams in CFStream is not documented |
||||||
|
by Apple, but our experiments show that it accords to the expected behaviors. |
||||||
|
With CFStream implementation, an event is always received when the underlying |
||||||
|
connection is no longer viable. For more detailed information and usages of |
||||||
|
CFStream implementation, refer to the |
||||||
|
[user guide](https://github.com/grpc/grpc/blob/master/src/objective-c/README-CFSTREAM.md). |
||||||
|
|
Loading…
Reference in new issue