iOS屏幕锁定后,监听套接字变成坏的文件描述符

4
我在我的应用程序中出于某种原因(与跨平台有关)使用TCP服务器(只绑定到127.0.0.1和一个随机端口)。我使用posix函数select检查是否有新的TCP连接。大多数情况下都正常工作,但是当我:1)按下主页按钮,锁定屏幕。2)解锁屏幕,立即按下应用程序图标返回应用程序时。 select函数会返回,告诉我可以处理我的服务器套接字,在我调用accept函数之后,它将返回-1,然后我通过getsockopt检查SO_ERROR,返回错误EBADF。以下是代码:
//listen fd is already nonblocking
if ((*pa = accept(*ps, addr, len)) != -1){
    printf("after accept %d %d\n", *pa, errno);
    return IO_DONE;
}

printf("after accept error %d %d %d %s\n", *ps, *pa, errno, strerror(errno));

int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (*ps, SOL_SOCKET, SO_ERROR, &error, &len);
if (retval != 0) {
    /* there was a problem getting the error code */
    fprintf(stderr, "error getting socket error code: %s\n", strerror(retval));
}

if (error != 0) {
    /* socket has a non zero error status */
    fprintf(stderr, "socket error: %s\n", strerror(error));
}

日志:

after accept error 5 -1 35 Resource temporarily unavailable
socket error: Bad file descriptor

我的测试设备是iPhone 4s,操作系统版本为iOS 8.4.1。

我已经阅读了https://developer.apple.com/library/ios/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/CommonPitfalls/CommonPitfalls.html,但没有发现任何问题。

那么,为什么会出现这种情况,如何解决呢?


你为什么要将监听套接字设置为非阻塞的?如果在调用accept之前使用select,accept将不会被阻塞。从accept中得到的错误并不是真正的错误,只是因为监听套接字是非阻塞的,指出接受的连接还没有准备好。将监听套接字设置为阻塞的,这个问题很可能就会消失。 - alk
2个回答

2

https://developer.apple.com/library/archive/technotes/tn2277/_index.html

监听套接字 在多任务环境中处理监听套接字非常简单:您的应用程序应在进入后台时关闭监听套接字,并在恢复前台时重新打开它。这样做有两个重要的原因:

一旦您的应用程序进入后台,它可能会被挂起。一旦挂起,它将无法正确地处理监听套接字上传入的连接。但是,内核仍然认为套接字处于活动状态。如果客户端连接到套接字,内核将接受连接,但您的应用程序将无法通过它进行通信。最终客户端将放弃连接,但这可能需要一段时间。 因此,在进入后台时最好关闭监听套接字,这将导致传入连接立即被内核拒绝。

如果系统挂起您的应用程序,然后稍后从监听套接字下方回收资源,那么即使应用程序已经恢复,它也不再监听连接。应用程序可能会或可能不会被通知此情况,这取决于它如何管理监听套接字。通常最好在应用程序进入后台时关闭监听套接字,以完全避免此问题。 请记住,当您的应用程序关闭监听套接字时,还应停止该套接字的任何Bonjour注册。


1

https://github.com/robbiehanson/CocoaHTTPServer/issues/10 我遇到了同样的问题。

应用程序需要观察UIApplicationWillResignActiveNotification和UIApplicationWillEnterForegroundNotification通知,并相应地停止和重新启动服务器。

保留初始服务器端口也很重要,因为Web视图无法从不同的端口加载资源。


谢谢@megar,我会尝试的。 - llj098

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接