很久以前参考了https://www.genivia.com/doc/soapdoc2.html 中的一段:
How to Create a Multi-Threaded Stand-Alone Service
完成了一个简单多线程服务器的编写。
但是一直以来服务器运行一段时间,接收一定量的请求后,就会出现服务器再也不返回的情况。
怀疑过是不是socket数量不够用了,后来跟踪发现还能正常listen。
怀疑是不是工作线程异常退出了,补充了所需的日志,也没有。
后来查询到,有人曾经也问过这个问题:https://sourceforge.net/p/gsoap2/bugs/844/
在gsoap的代码中加入日志,确实是在soap_serve卡住了,而卡住的位置就是在recv函数,位于文件stdsoap2.cpp的933行(72行):
1 frecv(struct soap *soap, char *s, size_t n) 2 { register int r; 3 register int retries = 100; /* max 100 retries with non-blocking sockets */ 4 soap->errnum = 0; 5 #if defined(__cplusplus) && !defined(WITH_LEAN) && !defined(WITH_COMPAT) 6 if (soap->is) 7 { if (soap->is->good()) 8 return soap->is->read(s, (std::streamsize)n).gcount(); 9 return 0; 10 } 11 #endif 12 if (soap_valid_socket(soap->socket)) 13 { for (;;) 14 { 15 #ifdef WITH_OPENSSL 16 register int err = 0; 17 #endif 18 #ifdef WITH_OPENSSL 19 if (soap->recv_timeout && !soap->ssl) /* SSL: sockets are nonblocking */ 20 #else 21 if (soap->recv_timeout) 22 #endif 23 { for (;;) 24 { r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, soap->recv_timeout); 25 if (r > 0) 26 break; 27 if (!r) 28 return 0; 29 r = soap->errnum; 30 if (r != SOAP_EINTR && r != SOAP_EAGAIN && r != SOAP_EWOULDBLOCK) 31 return 0; 32 } 33 } 34 #ifdef WITH_OPENSSL 35 if (soap->ssl) 36 { r = SSL_read(soap->ssl, s, (int)n); 37 if (r > 0) 38 return (size_t)r; 39 err = SSL_get_error(soap->ssl, r); 40 if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) 41 return 0; 42 } 43 else if (soap->bio) 44 { r = BIO_read(soap->bio, s, (int)n); 45 if (r > 0) 46 return (size_t)r; 47 return 0; 48 } 49 else 50 #endif 51 #ifdef WITH_GNUTLS 52 if (soap->session) 53 { r = (int)gnutls_record_recv(soap->session, s, n); 54 if (r >= 0) 55 return (size_t)r; 56 } 57 else 58 #endif 59 { 60 #ifndef WITH_LEAN 61 if ((soap->omode & SOAP_IO_UDP)) 62 { SOAP_SOCKLEN_T k = (SOAP_SOCKLEN_T)sizeof(soap->peer); 63 memset((void*)&soap->peer, 0, sizeof(soap->peer)); 64 r = recvfrom(soap->socket, s, (SOAP_WINSOCKINT)n, soap->socket_flags, (struct sockaddr*)&soap->peer, &k); /* portability note: see SOAP_SOCKLEN_T definition in stdsoap2.h */ 65 soap->peerlen = (size_t)k; 66 #ifndef WITH_IPV6 67 soap->ip = ntohl(soap->peer.sin_addr.s_addr); 68 #endif 69 } 70 else 71 #endif 72 r = recv(soap->socket, s, (int)n, soap->socket_flags); 73 #ifdef PALM 74 /* CycleSyncDisplay(curStatusMsg); */ 75 #endif 76 if (r >= 0) 77 return (size_t)r; 78 r = soap_socket_errno(soap->socket); 79 if (r != SOAP_EINTR && r != SOAP_EAGAIN && r != SOAP_EWOULDBLOCK) 80 { soap->errnum = r; 81 return 0; 82 } 83 } 84 #if defined(WITH_OPENSSL) 85 if (soap->ssl && err == SSL_ERROR_WANT_WRITE) 86 r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_SND | SOAP_TCP_SELECT_ERR, soap->recv_timeout ? soap->recv_timeout : 5); 87 else 88 #elif defined(WITH_GNUTLS) 89 if (soap->session && gnutls_record_get_direction(soap->session)) 90 r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_SND | SOAP_TCP_SELECT_ERR, soap->recv_timeout ? soap->recv_timeout : 5); 91 else 92 #endif 93 r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, soap->recv_timeout ? soap->recv_timeout : 5); 94 if (!r && soap->recv_timeout) 95 return 0; 96 if (r < 0) 97 { r = soap->errnum; 98 if (r != SOAP_EINTR && r != SOAP_EAGAIN && r != SOAP_EWOULDBLOCK) 99 return 0; 100 } 101 if (retries-- <= 0) 102 return 0; 103 #ifdef PALM 104 r = soap_socket_errno(soap->socket); 105 if (r != SOAP_EINTR && retries-- <= 0) 106 { soap->errnum = r; 107 return 0; 108 } 109 #endif 110 } 111 } 112 #ifdef WITH_FASTCGI 113 return fread(s, 1, n, stdin); 114 #else 115 #ifdef UNDER_CE 116 return fread(s, 1, n, soap->recvfd); 117 #else 118 #ifdef WMW_RPM_IO 119 if (soap->rpmreqid) 120 r = httpBlockRead(soap->rpmreqid, s, n); 121 else 122 #endif 123 #ifdef WIN32 124 r = _read(soap->recvfd, s, (unsigned int)n); 125 #else 126 r = read(soap->recvfd, s, (unsigned int)n); 127 #endif 128 if (r >= 0) 129 return (size_t)r; 130 soap->errnum = soap_errno; 131 return 0; 132 #endif 133 #endif 134 }
按照上面的网址链接,解决此问题的办法是:
You have to set the recv_timeout and send_timeout values as well. I/O may block otherwise
更神奇的是在这个文档中:https://www.genivia.com/tutorials.html
例子里面的soap则添加了超时处理!
int main() { struct soap *soap = soap_new1(SOAP_IO_KEEPALIVE); /* new context with HTTP keep-alive enabled */ SOAP_SOCKET m; /* master socket */ THREAD_TYPE tids[POOLSIZE]; /* thread pool */ int i; soap->accept_timeout = 24*60*60; /* quit after 24h of inactivity (optional) */ soap->send_timeout = soap->recv_timeout = 5; /* 5 sec socket idle timeout */ soap->transfer_timeout = 10; /* 10 sec message transfer timeout */
转自:https://blog.csdn.net/wayright/article/details/80608123
很久以前参考了https://www.genivia.com/doc/soapdoc2.html 中的一段:
How to Create a Multi-Threaded Stand-Alone Service
完成了一个简单多线程服务器的编写。
但是一直以来服务器运行一段时间,接收一定量的请求后,就会出现服务器再也不返回的情况。
怀疑过是不是socket数量不够用了,后来跟踪发现还能正常listen。
怀疑是不是工作线程异常退出了,补充了所需的日志,也没有。
后来查询到,有人曾经也问过这个问题:
https://sourceforge.net/p/gsoap2/bugs/844/
在gsoap的代码中加入日志,确实是在soap_serve卡住了,而卡住的位置就是在recv函数,位于文件stdsoap2.cpp的933行(72行):
frecv(struct soap *soap, char *s, size_t n) { register int r; register int retries = 100; /* max 100 retries with non-blocking sockets */ soap->errnum = 0; #if defined(__cplusplus) && !defined(WITH_LEAN) && !defined(WITH_COMPAT) if (soap->is) { if (soap->is->good()) return soap->is->read(s, (std::streamsize)n).gcount(); return 0; } #endif if (soap_valid_socket(soap->socket)) { for (;;) { #ifdef WITH_OPENSSL register int err = 0; #endif #ifdef WITH_OPENSSL if (soap->recv_timeout && !soap->ssl) /* SSL: sockets are nonblocking */ #else if (soap->recv_timeout) #endif { for (;;) { r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, soap->recv_timeout); if (r > 0) break; if (!r) return 0; r = soap->errnum; if (r != SOAP_EINTR && r != SOAP_EAGAIN && r != SOAP_EWOULDBLOCK) return 0; } } #ifdef WITH_OPENSSL if (soap->ssl) { r = SSL_read(soap->ssl, s, (int)n); if (r > 0) return (size_t)r; err = SSL_get_error(soap->ssl, r); if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) return 0; } else if (soap->bio) { r = BIO_read(soap->bio, s, (int)n); if (r > 0) return (size_t)r; return 0; } else #endif #ifdef WITH_GNUTLS if (soap->session) { r = (int)gnutls_record_recv(soap->session, s, n); if (r >= 0) return (size_t)r; } else #endif { #ifndef WITH_LEAN if ((soap->omode & SOAP_IO_UDP)) { SOAP_SOCKLEN_T k = (SOAP_SOCKLEN_T)sizeof(soap->peer); memset((void*)&soap->peer, 0, sizeof(soap->peer)); r = recvfrom(soap->socket, s, (SOAP_WINSOCKINT)n, soap->socket_flags, (struct sockaddr*)&soap->peer, &k); /* portability note: see SOAP_SOCKLEN_T definition in stdsoap2.h */ soap->peerlen = (size_t)k; #ifndef WITH_IPV6 soap->ip = ntohl(soap->peer.sin_addr.s_addr); #endif } else #endif r = recv(soap->socket, s, (int)n, soap->socket_flags); #ifdef PALM /* CycleSyncDisplay(curStatusMsg); */ #endif if (r >= 0) return (size_t)r; r = soap_socket_errno(soap->socket); if (r != SOAP_EINTR && r != SOAP_EAGAIN && r != SOAP_EWOULDBLOCK) { soap->errnum = r; return 0; } } #if defined(WITH_OPENSSL) if (soap->ssl && err == SSL_ERROR_WANT_WRITE) r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_SND | SOAP_TCP_SELECT_ERR, soap->recv_timeout ? soap->recv_timeout : 5); else #elif defined(WITH_GNUTLS) if (soap->session && gnutls_record_get_direction(soap->session)) r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_SND | SOAP_TCP_SELECT_ERR, soap->recv_timeout ? soap->recv_timeout : 5); else #endif r = tcp_select(soap, soap->socket, SOAP_TCP_SELECT_RCV | SOAP_TCP_SELECT_ERR, soap->recv_timeout ? soap->recv_timeout : 5); if (!r && soap->recv_timeout) return 0; if (r < 0) { r = soap->errnum; if (r != SOAP_EINTR && r != SOAP_EAGAIN && r != SOAP_EWOULDBLOCK) return 0; } if (retries-- <= 0) return 0; #ifdef PALM r = soap_socket_errno(soap->socket); if (r != SOAP_EINTR && retries-- <= 0) { soap->errnum = r; return 0; } #endif } } #ifdef WITH_FASTCGI return fread(s, 1, n, stdin); #else #ifdef UNDER_CE return fread(s, 1, n, soap->recvfd); #else #ifdef WMW_RPM_IO if (soap->rpmreqid) r = httpBlockRead(soap->rpmreqid, s, n); else #endif #ifdef WIN32 r = _read(soap->recvfd, s, (unsigned int)n); #else r = read(soap->recvfd, s, (unsigned int)n); #endif if (r >= 0) return (size_t)r; soap->errnum = soap_errno; return 0; #endif #endif }
按照上面的网址链接,解决此问题的办法是:
You have to set the recv_timeout and send_timeout values as well. I/O may block otherwise
更神奇的是在这个文档中:https://www.genivia.com/tutorials.html
例子里面的soap则添加了超时处理!
int main() { struct soap *soap = soap_new1(SOAP_IO_KEEPALIVE); /* new context with HTTP keep-alive enabled */ SOAP_SOCKET m; /* master socket */ THREAD_TYPE tids[POOLSIZE]; /* thread pool */ int i; soap->accept_timeout = 24*60*60; /* quit after 24h of inactivity (optional) */ soap->send_timeout = soap->recv_timeout = 5; /* 5 sec socket idle timeout */ soap->transfer_timeout = 10; /* 10 sec message transfer timeout */
转自:https://blog.csdn.net/wayright/article/details/80608123