如何在 iOS 上避免 SIGPIPE 信號(hào)導(dǎo)致的 crash (Avoiding SIGPIPE signal crash in iOS)

Update: 2015/12/8 補(bǔ)充參考鏈接

ps:翻譯自 APPLE 文檔,最后會(huì)附上連接和原文

當(dāng)使用 socket 進(jìn)行網(wǎng)絡(luò)連接時(shí),如果連接中斷,在默認(rèn)情況下,你的 process 會(huì)收到一個(gè) SIGPIPE 信號(hào)。如果你沒(méi)有處理這個(gè)信號(hào),app 會(huì)直接 crash!!!

有兩種方法可以解決這個(gè)問(wèn)題,任選其一:

  • 在全局范圍內(nèi)忽略這個(gè)信號(hào)
signal(SIGPIPE, SIG_IGN);

需要注意的是,這個(gè)方法是全局通用的,所有的 SIGPIPE 信號(hào)都將被忽略

  • 在一開(kāi)始的時(shí)候設(shè)置 socket 不要發(fā)送 SIGPIPE 信號(hào)
/// sock 就是設(shè)置不發(fā)送 `SIGPIPE` 信號(hào)的 socket 變量
int value = 1;
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));

附上 APPLE 原文(ref1):

Use POSIX sockets efficiently (if at all). If you are using POSIX sockets directly:

  • Handle or disable SIGPIPE.

When a connection closes, by default, your process receives a SIGPIPE signal. If your program does not handle or ignore this signal, your program will quit immediately. You can handle this in one of two ways:

  • Ignore the signal globally with the following line of code:
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):
int value = 1;
setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));

For maximum compatibility, you should set this flag on each incoming socket immediately after calling accept in addition to setting the flag on the listening socket itself.


下面一段提到使用 GCD 時(shí)什么時(shí)候設(shè)置 SO_NOSIGPIPE 的時(shí)機(jī)(ref2)

Handling Events with Grand Central Dispatch

GCD allows you to perform operations asynchronously, and provides an event queue mechanism for determining when to read data from the socket. After creating the listening socket, a GCD-based server should:

  1. Call dispatch_source_create to create a dispatch source for the listening socket, specifying DISPATCH_SOURCE_TYPE_READ as the source type.
  2. Call dispatch_source_set_event_handler (or dispatch_source_set_event_handler_f and dispatch_set_context) to set a handler that gets called whenever a new connection arrives on the socket.
  3. When the listen socket handler is called (upon a new connection), it should:
    • Call accept. This function fills a new sockaddr structure with information about the connection and returns a new socket for that connection.
      If desired, call ntohl(my_sockaddr_obj.sin_addr.s_addr) to determine the client’s IP address.
    • Call dispatch_source_create to create a dispatch source for the client socket, specifying DISPATCH_SOURCE_TYPE_READ as the source type.
    • Call setsockopt to set the SO_NOSIGPIPE flag on the socket.
    • Call dispatch_source_set_event_handler (or dispatch_source_set_event_handler_f and dispatch_set_context) to set a handler that gets called whenever the state of the connection changes.
  4. In the client socket handler, call dispatch_async or dispatch_async_f and pass a block that calls read on the socket to grab any new data, then handle that data appropriately. This block can also send responses by calling write on the socket.

ref:

  1. Avoiding Common Networking Mistakes: https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/CommonPitfalls/CommonPitfalls.html
  2. Using Sockets and Socket Streams: https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/UsingSocketsandSocketStreams.html#//apple_ref/doc/uid/CH73-SW1
  3. Ignore SIGPIPE signal on iOS
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容