在我的應用程序的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