草庐IT

c++ - Linux TCP 服务器问题 C++

coder 2023-09-19 原文

一个多月以来,我一直在努力解决这个问题。我别无选择。 我有一台服务器可以收听许多多播 channel (100ish)。每个套接字都是它自己的线程。然后我有一个客户端监听器(单线程),它处理同一服务器内的所有传入连接、断开连接和客户端消息传递。这个想法是客户端进来,连接,从多播 channel 请求数据,然后我将数据发送回客户端。客户端保持连接,我将 UDP 数据中继回客户端。客户端可以请求 UDP 或 TCP 具有用于数据中继的协议(protocol)。有一段时间,这在几周内都运行良好。我们做了一些代码和内核更改,现在我们无法弄清楚哪里出了问题。

服务器将运行数小时,全天连接数百个客户端。但在某个时候,服务器会随机停止。停止,我的意思是:所有 UDP 套接字停止接收/处理数据(tcpdump 显示数据仍在框内),client_listener 线程停止接收客户端数据包。但!!!主 client_listener 套接字仍然可以在主套接字上接收新连接和新断开连接。在新连接上,主套接字能够将“连接已建立”数据包发送回客户端,但是当客户端响应时,选择永远不会返回。

如果有人愿意,我可以发布代码。如果有人有任何建议在哪里看,或者这听起来像什么。请告诉我。

如有任何问题,请提出。

谢谢。


我想分享我的 TCP 服务器代码: 这是一个单线程。几个小时都可以正常工作,然后我只会收到“新连接”和“断开连接”。不会有客户端数据包进来。

int opt = 1;
  int addrlen;
  int sd;
  int max_sd;
  int valread;
  int activity;
  int new_socket;
  char buffer[MAX_BUFFER_SIZE];
  int client_socket[m_max_clients];
  struct sockaddr_in address;

  fd_set readfds;
  for(int i = 0; i<m_max_clients; i++)
  {
    client_socket[i]=0;
  }

  if((m_master_socket = socket(AF_INET,SOCK_STREAM,0))==0)
    LOG(FATAL)<<"Unable to create master socket";

  if(setsockopt(m_master_socket,SOL_SOCKET,SO_REUSEADDR,(char*)&opt,sizeof(opt))<0)
    LOG(FATAL)<<"Unable to set master socket";

  address.sin_family = AF_INET;
  address.sin_addr.s_addr = INADDR_ANY;
  address.sin_port = htons(m_listenPort);

  if(bind(m_master_socket,(struct sockaddr*)& address, sizeof(address))!=0)
    LOG(FATAL)<<"Unable to bind master socket";

  if(listen(m_master_socket,SOMAXCONN)!=0)
    LOG(FATAL)<<"listen() failed with err";

  addrlen = sizeof(address);
  LOG(INFO)<<"Waiting for connections......";

while(true)
  {
    FD_ZERO(&readfds);

    FD_SET(m_master_socket, &readfds);
    max_sd = m_master_socket;

    for(int i = 0; i<m_max_clients; i++)
    {
      sd = client_socket[i];

      if(sd > 0)
        FD_SET(sd, &readfds);

      if(sd>max_sd)
        max_sd = sd;
    }

    activity = select(max_sd+1,&readfds,NULL,NULL,NULL);

    if((activity<0)&&(errno!=EINTR))
    {
    //  int err = errno;
  //    LOG(ERROR)<<"SELECT ERROR:"<<activity<<" "<<err;
      continue;
    }

    if(FD_ISSET(m_master_socket, &readfds))
    {
      if((new_socket = accept(m_master_socket,(struct sockaddr*)&address, (socklen_t*)&addrlen))<0)
        LOG(FATAL)<<"ERROR:ACCEPT FAILED!";

      LOG(INFO)<<"New Connection, socket fd is (" << new_socket << ") client_addr:" << inet_ntoa(address.sin_addr) << " Port:" << ntohs(address.sin_port);
      for(int i =0;i<m_max_clients;i++)
      {
        if(client_socket[i]==0)
        {
          //try to set the socket to non blocking, tcp nagle and keep alive
          if ( !SetSocketBlockingEnabled(new_socket, false) )
            LOG(INFO)<<"UNABLE TO SET NON-BLOCK: ("<<new_socket<<")" ;
          if ( !SetSocketNoDelay(new_socket,false) )
            LOG(INFO)<<"UNABLE TO SET DELAY: ("<<new_socket<<")" ;
//           if ( !SetSocketKeepAlive(new_socket,true) )
//            LOG(INFO)<<"UNABLE TO SET KeepAlive: ("<<new_socket<<")" ;

          ClientConnection* con = new ClientConnection(m_mocSrv, m_udpPortGenerator, inet_ntoa(address.sin_addr), ntohs(address.sin_port), new_socket);
          if(con->login())
          {
            client_socket[i] = new_socket;
            m_clientConnectionSocketMap[new_socket] = con;
            LOG(INFO)<<"Client Connection Logon Complete";
          }
          else
            delete con;
          break;
        }
      }//for
    }
    else
    {
      try{
        for(int i = 0; i<m_max_clients; i++)
        {
          sd = client_socket[i];
          if(FD_ISSET(sd,&readfds))
          {
            if ( (valread = recv(sd, buffer, sizeof(buffer),MSG_DONTWAIT|MSG_NOSIGNAL)) <= 0 )
            {
             //remove from the fd listening set
              LOG(INFO)<<"RESET CLIENT_SOCKET:("<<sd<<")";
              client_socket[i]=0;
              handleDisconnect(sd,true);
           }
           else
           {
             std::map<int, ClientConnection*>::iterator client_connection_socket_iter = m_clientConnectionSocketMap.find(sd);
             if(client_connection_socket_iter != m_clientConnectionSocketMap.end())
             {
               client_connection_socket_iter->second->handle_message(buffer, valread);
               if(client_connection_socket_iter->second->m_logoff)
               {
                  LOG(INFO)<<"SOCKET LOGGED OFF:"<<sd;
                  client_socket[i]=0;
                  handleDisconnect(sd,true);
               }
             }
             else
             {
                LOG(ERROR)<<"UNABLE TO FIND SOCKET DESCRIPTOR:"<<sd;
             }
           }
          }
        }
      }catch(...)
      {
        LOG(ERROR)<<"EXCEPTION CATCH!!!";
      }
    }
  }

最佳答案

根据所提供的信息,我将声明以下内容:

  • 不要为每个连接使用一个线程。由于您使用的是 Linux,因此请使用 EPOLL Edge Triggered Multiplexing。大多数较新的 Web 框架都使用这种技术。有关更多信息,请查看 10K Problem . 通过从等式中消除线程,您可以消除死锁的可能性并降低调试的复杂性/担心线程安全变量。
  • 确保每个连接在完成后完全关闭。
  • 确保升级后 iptables 中没有弹出一些新的防火墙规则。
  • 检查网络上的所有防火墙,看它们是否限制某些类型的事件(升级后您的服务器是否使用新 IP?)

简而言之,我会把钱花在线程死锁和/或饥饿上。我亲自进行了实验,其中我使用 Epoll 创建了多线程服务器与单线程服务器。结果日日夜夜,Epoll 摒弃了多线程实现(对于 I/O)并使代码更易于编写、调试和维护。

关于c++ - Linux TCP 服务器问题 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37326188/

有关c++ - Linux TCP 服务器问题 C++的更多相关文章

  1. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  2. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  3. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  4. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  5. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  6. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  7. ruby - Fast-stemmer 安装问题 - 2

    由于fast-stemmer的问题,我很难安装我想要的任何ruby​​gem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=

  8. ruby-on-rails - 启动 Rails 服务器时 ImageMagick 的警告 - 2

    最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru

  9. ruby-on-rails - s3_direct_upload 在生产服务器中不工作 - 2

    在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo

  10. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

随机推荐