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 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

原文地址:https://www.cnblogs.com/liushui-sky/p/11889178.html