在我的 iOS 应用程序(DLNA 媒体播放器)中,我看到了一个我不明白的挂起......我希望有人能解释一下。
我的应用程序是在位于 C++ 库之上的 Objective C 中构建的,其中一部分是 libupnp。为了记录,在查看下面的代码时,设置了编译标志 SO_NOSIGPIPE。
从广义上讲,该应用程序运行良好,至少在运行 iOS 6 的 iPod 和我的 iPad 上运行良好。它可以处理所有媒体播放器之类的事情。
编辑:我对 iPhone 4 上的操作系统有误,我认为它是 6.x,但它是 5.1.1,值得。
当我开始在 iPhone 4 (iOS 5.1.1) 和 iPhone 5 (iOS 6) 上测试我的应用程序时,就会出现问题......这告诉我我的代码中存在时间问题。
用户选择要在远程数字媒体接收器 (DMR) 上播放/显示的媒体项目。
我的代码调用libupnp,创建soap 命令来实现这一点。然后它调用 http_RequestAndResponse(),它创建套接字,connect()s 到主机,并调用 http_SendMessage,它调用 sock_read_write(我将在后面的消息中包含这个函数)来发送我构建的请求(POST 命令播放 DMR 上的媒体)。然后,使用同一个套接字,调用 http_RecvMessage(它再次调用 sock_read_write() 来接收字节)。此时,调用 select() 等待 DMR 对播放命令做出响应。
在不同的线程上,libupnp 的 Web 服务器收到对我们刚才说要播放的媒体文件位的请求。所以在另一个线程上,我用字节调用 http_SendMessage 来响应请求,它调用 sock_read_write() 将字节写入客户端。
sock_read_write 中的这个 send() 挂起。它不仅挂起 libupnp,而且意味着任何线程上的套接字上都没有更多的通信。
这些挂起的套接字似乎没有超时、死亡或以其他方式终止。当然,它是我正在构建的 DLNA 媒体播放器,关于世界状态的许多命令和报告都通过这些套接字传输,所以我的应用程序实际上变成了僵尸:它响应鼠标点击等等,但是你不能做任何有意义的事情。
我试过让 send() 非阻塞。我已经尝试调用 fcntrl(sock,F_SETFL, O_NONBLOCK) 将其设置为非阻塞,并在调用 send() 之前如果因任何原因失败则返回。
我已经尝试在 send() 上使用类似 MSG_NOWAIT(对 iOS 没有影响)的标志来发送()。
这似乎是一个时间问题。在 iPad 和 iPod 上,我可以一直播放音乐,直到奶牛回家。在 iPhone 4 和 iPhone 5 上,我遇到了挂起。
有什么建议么?(如果您告诉我哪些具体回答了这个问题,我们很乐意接受对 RTFM、阅读手册页、阅读书籍等的建议……)
哦,sock_read_write() 的代码(来自 libupnp 1.6.18):
/*!
* \brief Receives or sends data. Also returns the time taken to receive or
* send data.
*
* \return
* \li \c numBytes - On Success, no of bytes received or sent or
* \li \c UPNP_E_TIMEDOUT - Timeout
* \li \c UPNP_E_SOCKET_ERROR - Error on socket calls
*/
static int sock_read_write(
/*! [in] Socket Information Object. */
SOCKINFO *info,
/*! [out] Buffer to get data to or send data from. */
char *buffer,
/*! [in] Size of the buffer. */
size_t bufsize,
/*! [in] timeout value. */
int *timeoutSecs,
/*! [in] Boolean value specifying read or write option. */
int bRead)
{
int retCode;
fd_set readSet;
fd_set writeSet;
struct timeval timeout;
long numBytes;
time_t start_time = time(NULL);
SOCKET sockfd = info->socket;
long bytes_sent = 0;
size_t byte_left = (size_t)0;
ssize_t num_written;
if (*timeoutSecs < 0)
return UPNP_E_TIMEDOUT;
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
if (bRead)
FD_SET(sockfd, &readSet);
else
FD_SET(sockfd, &writeSet);
timeout.tv_sec = *timeoutSecs;
timeout.tv_usec = 0;
while (TRUE) {
if (*timeoutSecs == 0)
retCode = select(sockfd + 1, &readSet, &writeSet,
NULL, NULL);
else
retCode = select(sockfd + 1, &readSet, &writeSet,
NULL, &timeout);
if (retCode == 0)
return UPNP_E_TIMEDOUT;
if (retCode == -1) {
if (errno == EINTR)
continue;
return UPNP_E_SOCKET_ERROR;
} else
/* read or write. */
break;
}
#ifdef SO_NOSIGPIPE
{
int old;
int set = 1;
socklen_t olen = sizeof(old);
getsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &old, &olen);
setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(set));
#endif
if (bRead) {
/* read data. */
numBytes = (long)recv(sockfd, buffer, bufsize, MSG_NOSIGNAL);
} else {
byte_left = bufsize;
bytes_sent = 0;
while (byte_left != (size_t)0) {
/* write data. */
num_written = send(sockfd,
buffer + bytes_sent, byte_left,
MSG_DONTROUTE | MSG_NOSIGNAL);
if (num_written == -1) {
#ifdef SO_NOSIGPIPE
setsockopt(sockfd, SOL_SOCKET,
SO_NOSIGPIPE, &old, olen);
#endif
return (int)num_written;
}
byte_left -= (size_t)num_written;
bytes_sent += num_written;
}
numBytes = bytes_sent;
}
#ifdef SO_NOSIGPIPE
setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &old, olen);
}
#endif
if (numBytes < 0)
return UPNP_E_SOCKET_ERROR;
/* subtract time used for reading/writing. */
if (*timeoutSecs != 0)
*timeoutSecs -= (int)(time(NULL) - start_time);
return (int)numBytes;
}
谢谢!
-肯