Files
knowledge-kit/Chapter5 - Network/5.5.md

4.0 KiB
Raw Blame History

iOS 端底层网络错误

本篇文章主要记录在 iOS 侧,一些底层网络问题的产生和解决。包括一些 socket 的疑难杂症

典型案例

1. Socket 断开后会收到 SIGPIPE 类型的信号,如果不处理会 crash

同事问了我一个问题,说收到一个 crash 信息,去 mpaas 平台看到如下的 crash 信息

2021-04-06-NetworkFatlError.png

看了代码显示在某某文件的313行代码代码如下

2021-04-06-NetworkFatlError.png

Socket 属于网络最底层的实现,一般我们开发不需要用到,但是用到了就需要小心翼翼,比如 Hook 网络层、长链接等。查看官方文档会说看到一些说明。

当使用 socket 进行网络连接时,如果连接中断,在默认情况下, 进程会收到一个 SIGPIPE 信号。如果你没有处理这个信号app 会 crash。

Mach 已经通过异常机制提供了底层的陷进处理,而 BSD 则在异常机制之上构建了信号处理机制。硬件产生的信号被 Mach 层捕捉,然后转换为对应的 UNIX 信号,为了维护一个统一的机制,操作系统和用户产生的信号首先被转换为 Mach 异常,然后再转换为信号。

Mach 异常都在 host 层被 ux_exception 转换为相应的 unix 信号,并通过 threadsignal 将信号投递到出错的线程。

Mach 异常处理以及转换为 Unix 信号的流程

有2种解决办法

  • Ignore the signal globally with the following line of code.(在全局范围内忽略这个信号 。缺点是所有的 SIGPIPE 信号都将被忽略)

    signal(SIGPIPE, SIG_IGN);
    
  • Tell the socket not to send the signal in the first place with the following lines of code (substituting the variable containing your socket in place of sock)(告诉 socket 不要发送信号SO_NOSIGPIPE)

    int value = 1;
    setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));
    

其中:EPIPE 是 socket send 函数可能返回的错误码之一。如果发送数据的话会在 Client 端触发 RST指Client端的 FIN_WAIT_2 状态超时后连接已经销毁的情况导致send操作返回 EPIPEerrno 32错误并触发 SIGPIPE 信号(默认行为是 Terminate)。

What happens if the client ignores the error return from readline and writes more data to the server? This can happen, for example, if the client needs to perform two writes to the server before reading anything back, with the first write eliciting the RST.

The rule that applies is: When a process writes to a socket that has received an RST, the SIGPIPE signal is sent to the process. The default action of this signal is to terminate the process, so the process must catch the signal to avoid being involuntarily terminated.

If the process either catches the signal and returns from the signal handler, or ignores the signal, the write operation returns EPIPE.

UNP(unix network program) 建议应用根据需要处理 SIGPIPE信号,至少不要用系统缺省的处理方式处理这个信号,系统缺省的处理方式是退出进程,这样你的应用就很难查处处理进程为什么退出。对 UNP 感兴趣的可以查看:http://www.unpbook.com/unpv13e.tar.gz

下面是2个苹果官方文档描述了 socket 和 SIGPIPE 信号,以及最佳实践:

Avoiding Common Networking Mistakes

Using Sockets and Socket Streams

2. ...