Updated doc

pull/14650/head
Muxi Yan 7 years ago
parent f613be8e82
commit 965a015b05
  1. 53
      src/objective-c/NetworkBehavior.md
  2. 86
      src/objective-c/NetworkTransitionBehavior.md

@ -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…
Cancel
Save