如何在 iOS 上避免 SIGPIPE 信號導致的 crash (Avoiding SIGPIPE signal crash in iOS)

http://www.jianshu.com/p/1957d2b18d2c



ps:翻譯自 APPLE 文檔,最後會附上連接和原文

當使用 socket 進行網絡連接時,如果連接中斷,在默認情況下,你的 process 會收到一個 SIGPIPE 信號。如果你沒有處理這個信號,app 會直接 crash!!!

有兩種方法可以解決這個問題,任選其一:

  • 在全局範圍內忽略這個信號
signal(SIGPIPE, SIG_IGN);

需要注意的是,這個方法是全局通用的,所有的 SIGPIPE 信號都將被忽略

  • 在一開始的時候設置 socket 不要發送 SIGPIPE 信號
/// sock 就是設置不發送 `SIGPIPE` 信號的 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 時什麼時候設置 SO_NOSIGPIPE 的時機(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


文/likid1412(簡書作者)
原文鏈接:http://www.jianshu.com/p/1957d2b18d2c
著作權歸作者所有,轉載請聯繫作者獲得授權,並標註“簡書作者”。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章