在我的应用程序的iOS(DLNA媒体播放器),我看到一个挂不明白...我希望有人可以阐明它。ios多线程套接字libupnp挂在发送()
我的应用程序构建在Objective C中,它位于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()到主机,并调用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;
}
谢谢!
-Ken