Chinaunix

标题: 大量客户端重新连接 导致服务器端死锁,机器死机 [打印本页]

作者: usbzip    时间: 2011-09-05 11:39
标题: 大量客户端重新连接 导致服务器端死锁,机器死机
本帖最后由 usbzip 于 2011-09-05 11:54 编辑

tcp服务器端程序,平时连接的客户端有600多个,每隔30秒客户端发送一次数据。
服务器端有个map负责管理客户端ip和编号
使用了epoll模型
使用了线程池 线程池大小是16
epoll接收到socket事件,向线程池中派发任务。
企业adls 带宽2m
两者之间通过tcp通讯


现象
在工作正常的情况下,每分钟大约有5个左右的客户端会重新连接
有时会出现在及短的时间内(几秒内),大量(感觉更像是全部)客户端重新连接的现象,一个多月出现一次,期间服务端程序一直在工作。
16个线程都会对map进行添加和删除操作,程序进入死锁。

问题
这种突发的大量重连像是由什么引起的??  
象这种服务器端的应用如何减少死锁的情况?
谢谢大家
作者: 雨过白鹭洲    时间: 2011-09-05 11:42
客户端与服务器之间的连接是?
作者: drangon    时间: 2011-09-05 11:44
标题写“崩溃”,内容写“死锁”,要崩溃了。。。。

不同的错误现象不同的原因,具体问题具体分析罗
作者: usbzip    时间: 2011-09-05 11:46
客户端与服务器之间的连接是?
雨过白鹭洲 发表于 2011-09-05 11:42



    tcp通讯
作者: usbzip    时间: 2011-09-05 11:46
标题写“崩溃”,内容写“死锁”,要崩溃了。。。。

不同的错误现象不同的原因,具体问题具体分析罗
drangon 发表于 2011-09-05 11:44


机器死掉了 只能重启
作者: crazyhadoop    时间: 2011-09-05 12:05
回复 1# usbzip


    太笼统了啊!估计还要好好的排查下代码流程
作者: usbzip    时间: 2011-09-05 13:13
代码
signal(SIGCHLD, SIG_IGN);
  int enums,j,Newfd,listen_index,epollfd,listenq,epollsize,n;
  struct sockaddr_in TheirAddr;
  socklen_t len;
  epollsize = (LGWTCPConf.GetConf()).MaxPollSize;
  listenq = (LGWTCPConf.GetConf()).MaxListenQ;
  ServerInit();

  struct epoll_event ev;
  struct epoll_event events[1000];
  epollfd = epoll_create(epollsize);
  LOG4CPLUS_INFO(log.GetLogInstance(),"epoll create "<< epollfd);
  len = sizeof(struct sockaddr_in);
  ev.events = EPOLLIN | EPOLLET;
  ev.data.fd = LGWTCPSock;
  if (epoll_ctl(epollfd, EPOLL_CTL_ADD, LGWTCPSock, &ev) < 0) {
    LOG4CPLUS_INFO(log.GetLogInstance(),"epoll set insertion error\n");
    return -1;
  }
  LOG4CPLUS_INFO(log.GetLogInstance(),"start main loop \n");
  while(1)
  {
    enums = epoll_wait(epollfd, events, listenq, 20);
    if (enums == -1)
    {
        printf("errno=%d,%s\r\n",errno,strerror(errno));
        if(errno==EINTR)
        {
            continue;
        }
        perror("epoll_wait");
    }
    else if(enums==0)
    {
        continue;
    }
    for (n = 0; n < enums; ++n) {
      listen_index=events[n].data.u32;
      if (events[n].data.fd == LGWTCPSock) {
        do {
            Newfd = accept(LGWTCPSock, (struct sockaddr *) &TheirAddr,&len);
            if (Newfd < 0) {
                break;
            }
            printf("Connect from %s:%d Newfd %d\n", inet_ntoa(TheirAddr.sin_addr),htons(TheirAddr.sin_port),Newfd);
            setnonblocking(Newfd);
            int keepCount = 3;
            int keepInterval = 5;
            int keepIdle = 600;
            int keepAlive = 1;
            setsockopt(Newfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
            setsockopt(Newfd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
            setsockopt(Newfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
            setsockopt(Newfd, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));
            ev.events = EPOLLIN | EPOLLET;
            ev.data.fd = Newfd;
            if (epoll_ctl(epollfd, EPOLL_CTL_ADD, Newfd, &ev) < 0) {
              fprintf(stderr, " socket '%d' add epoll error! %s\n",Newfd, strerror(errno));

            }
        }while(Newfd>0);
      }
      else if(events[n].events & EPOLLIN)
      {
        for(j=0;j<MAXTHREAD;j++)
        {
          if(0==s_thread_para[j][0]) break;
        }
        if(j>MAXTHREAD)
        {
          LOG4CPLUS_INFO(log.GetLogInstance(),"thread pool is full!\n");
          close(Newfd);
          continue;
        }
        pthread_mutex_lock(&mutex);
        s_thread_para[j][0]=1;
        s_thread_para[j][1]=events[n].data.fd;
        pthread_mutex_unlock(&mutex);
        pthread_mutex_unlock(s_mutex+j);
      }
    }
  }

这段有什么问题么
作者: usbzip    时间: 2011-09-05 13:14
代码
signal(SIGCHLD, SIG_IGN);
  int enums,j,Newfd,listen_index,epollfd,listenq,epollsize,n;
  struct sockaddr_in TheirAddr;
  socklen_t len;
  epollsize = (LGWTCPConf.GetConf()).MaxPollSize;
  listenq = (LGWTCPConf.GetConf()).MaxListenQ;
  ServerInit();

  struct epoll_event ev;
  struct epoll_event events[1000];
  epollfd = epoll_create(epollsize);
  LOG4CPLUS_INFO(log.GetLogInstance(),"epoll create "<< epollfd);
  len = sizeof(struct sockaddr_in);
  ev.events = EPOLLIN | EPOLLET;
  ev.data.fd = LGWTCPSock;
  if (epoll_ctl(epollfd, EPOLL_CTL_ADD, LGWTCPSock, &ev) < 0) {
    LOG4CPLUS_INFO(log.GetLogInstance(),"epoll set insertion error\n");
    return -1;
  }
  LOG4CPLUS_INFO(log.GetLogInstance(),"start main loop \n");
  while(1)
  {
    enums = epoll_wait(epollfd, events, listenq, 20);
    if (enums == -1)
    {
        printf("errno=%d,%s\r\n",errno,strerror(errno));
        if(errno==EINTR)
        {
            continue;
        }
        perror("epoll_wait");
    }
    else if(enums==0)
    {
        continue;
    }
    for (n = 0; n < enums; ++n) {
      listen_index=events[n].data.u32;
      if (events[n].data.fd == LGWTCPSock) {
        do {
            Newfd = accept(LGWTCPSock, (struct sockaddr *) &TheirAddr,&len);
            if (Newfd < 0) {
                break;
            }
            printf("Connect from %s:%d Newfd %d\n", inet_ntoa(TheirAddr.sin_addr),htons(TheirAddr.sin_port),Newfd);
            setnonblocking(Newfd);
            int keepCount = 3;
            int keepInterval = 5;
            int keepIdle = 600;
            int keepAlive = 1;
            setsockopt(Newfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
            setsockopt(Newfd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
            setsockopt(Newfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
            setsockopt(Newfd, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));
            ev.events = EPOLLIN | EPOLLET;
            ev.data.fd = Newfd;
            if (epoll_ctl(epollfd, EPOLL_CTL_ADD, Newfd, &ev) < 0) {
              fprintf(stderr, " socket '%d' add epoll error! %s\n",Newfd, strerror(errno));

            }
        }while(Newfd>0);
      }
      else if(events[n].events & EPOLLIN)
      {
        for(j=0;j<MAXTHREAD;j++)
        {
          if(0==s_thread_para[j][0]) break;
        }
        if(j>MAXTHREAD)
        {
          LOG4CPLUS_INFO(log.GetLogInstance(),"thread pool is full!\n");
          close(Newfd);
          continue;
        }
        pthread_mutex_lock(&mutex);
        s_thread_para[j][0]=1;
        s_thread_para[j][1]=events[n].data.fd;
        pthread_mutex_unlock(&mutex);
        pthread_mutex_unlock(s_mutex+j);
      }
    }
  }

这段有什么问题么
作者: ydfgic    时间: 2011-09-05 14:47
for(j=0;j<MAXTHREAD;j++)
        {
          if(0==s_thread_para[j][0]) break;
        }
        if(j>MAXTHREAD)
        {
          LOG4CPLUS_INFO(log.GetLogInstance(),"thread pool is full!\n");
          close(Newfd);
          continue;
这段纯粹是有问题:
1.你的线程池只能接收MAXTHREAD 个任务吗?这是什么设计?线程池是从任务队列里取数据的。
2. if(j>MAXTHREAD)  close(Newfd); 这个就是你为什么会重置连接的原因。 你的Newfd是什么值,你搞清楚没?还有没有看见你在这个elseif 里赋值给它。
3. 代码是不是不全? 没有见到pthread_mutex_unlock(s_mutex+j); 加锁的地方,死锁是这里发生的?
作者: xiao_cui2000    时间: 2011-09-05 15:05
for(j=0;j<MAXTHREAD;j++)
if(j>MAXTHREAD)

j==MAXTHREAD?
作者: usbzip    时间: 2011-09-06 10:13
谢谢大家的回答
if(j>MAXTHREAD) 是一个严重的bug 一直没有发现
我想出现问题的地方应该是多线程抢用map数据造成了 死锁




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2