GSOAP服务卡住?

很久以前参考了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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

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则添加了超时处理!

1
2
3
4
5
6
7
8
9
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 */

我就想问官方,你的例子为啥不能一起更新呢?