• 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

  • 相关阅读:
    [译]微服务-Martin Fowler(转)
    SpringBoot注解最全详解(整合超详细版本)(转)
    操作系统中的句柄是什么?(转)
    用户态和核心态(转)
    进程、线程、协程(转)
    IO中同步与异步,阻塞与非阻塞区别(转)
    HTML5常见的取值与单位
    C++实现词法分析器
    用C语言编写一个简单的词法分析程序
    Java面向对象详解
  • 原文地址:https://www.cnblogs.com/liushui-sky/p/11889178.html
Copyright © 2020-2023  润新知