Linux TCP服务器发布C++

Linux TCP服务器发布C++,c++,linux,tcp,udp,tcpserver,C++,Linux,Tcp,Udp,Tcpserver,一个多月来我一直在努力解决这个问题。我没有别的地方可去。 我有一个服务器,可以监听许多多播频道。每个套接字都有自己的线程。然后我有一个客户端侦听器单线程,它处理同一服务器内的所有传入连接、断开连接和客户端消息传递。其思想是客户端进入、连接、请求来自多播通道的数据,然后我将数据发送回客户端。客户端保持连接,我将UDP数据中继回客户端。客户端可以请求UDP,也可以请求TCP具有数据中继协议。在某一点上,这是一个完美的工作了几个星期。我们做了一些代码和内核更改,现在我们无法找出哪里出了问题 服务器将运

一个多月来我一直在努力解决这个问题。我没有别的地方可去。 我有一个服务器,可以监听许多多播频道。每个套接字都有自己的线程。然后我有一个客户端侦听器单线程,它处理同一服务器内的所有传入连接、断开连接和客户端消息传递。其思想是客户端进入、连接、请求来自多播通道的数据,然后我将数据发送回客户端。客户端保持连接,我将UDP数据中继回客户端。客户端可以请求UDP,也可以请求TCP具有数据中继协议。在某一点上,这是一个完美的工作了几个星期。我们做了一些代码和内核更改,现在我们无法找出哪里出了问题

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

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

如果你有任何问题,请提问

多谢各位

我想分享我的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边缘触发多路复用。大多数较新的web框架都使用这种技术。有关更多信息,请查看。 通过从等式中删除线程,您消除了死锁的可能性,并降低了调试/担心线程安全变量的复杂性。 确保完成后的每个连接完全关闭。 确保升级后iptables中没有出现一些新的防火墙规则。 检查网络上的任何防火墙,查看它们是否限制某些类型的活动自升级后您的服务器是否位于新的IP上?
简言之,我会把钱放在线程死锁和/或饥饿上。我亲自进行了一些实验,其中我使用Epoll创建了多线程服务器,而不是单线程服务器。结果,无论白天还是黑夜,Epoll都将I/O的多线程实现吹走,使代码更易于编写、调试和维护

一旦使用完所有资源、套接字、内存、文件等,您会释放它们吗?逐行检查代码,查找您分配资源的所有位置,或为您分配资源的所有位置accept、malloc、new、std::vector::push_back等,确保该资源有匹配的版本。谢谢Joachim,我会查找的。查看htop时没有内存泄漏。这种情况也会发生,我看到的只是没有客户端数据包的新连接或断开连接,然后它会清理自己一段时间,然后直接回到坏状态并保持在那里。每个套接字都是它自己的线程坏主意。你可以用一个线程来完成。查阅线程的数量应该与您拥有的内核数量大致相同。我们对代码和内核进行了一些更改,但现在我们无法确定出哪里出了问题。注意:您可以使用源代码管理回滚代码?许多线程加上大部分内容偶尔会因为没有明显的原因而停止,听起来很像您遇到了死锁问题。i、 e.线程A持有锁1并等待获取锁2,而线程B持有锁2并等待获取锁1,因此两者都被卡住。虽然有100多个线程,但情况可能更复杂。解决方案是确保同时持有多个锁的所有线程总是以相同的顺序获取它们。。。说起来容易做起来难,因为并非所有锁获取都是显式的。乔纳森避免线程的想法可能更好。谢谢乔纳森。我目前正在尝试使用valgrind,看看是否能找到任何东西。我相信我不清楚到底发生了什么。我收听100个UDP频道。每一条都是自己的线索。至于客户端,它是一个单线程。我最初使用的是epoll。有了这个bug,并且对epoll不太熟悉,我使用select更改为FD_SET。对于所有新连接、客户端数据包和断开连接,仍然是单线程的。这就是我感到困惑的地方:当服务器处于这种糟糕的状态时,我仍然能够处理新的连接和断开连接。但是没有客户端数据包。我仍然建议使用几个线程。Epoll可以处理七个问题 ral文件描述符,由于套接字被分类为文件描述符,因此它可以处理多个通道。请看这篇文章: