客户端执行close()后服务器的文件描述符崩溃

时间:2013-07-04 17:37:22

标签: c sockets select

我在关闭套接字时遇到问题。

我有一个可以接受n个客户端的服务器,但是当其中一个服务器完成时,服务器的套接字会抛出“坏文件描述符”。我在另一台服务器上有相同的算法,没有问题,我猜不出问题出在哪里,帮助!

这是一些代码。请注意,服务器不会将新客户端放在select的监视中,只需将它们放在另一个列表中即可。

将套接字置于主集中的行不应该在那里(新客户端连接后的那个)。

服务器

void planificador(t_scheduler_queue *scheduler_queue)
{

  int j, len, rc, on = 1;
  int listen_sd, max_sd, new_sd;
  int desc_ready, end_server = FALSE;
  int close_conn;
  char buffer[MAXSIZE];
  struct sockaddr_in addr;
  struct timeval timeout;
  fd_set master_set;
  fd_set working_set;

  /*************************************************************/
  /* Create an AF_INET stream socket to receive incoming */
  /* connections on */
  /*************************************************************/
  listen_sd = socket(AF_INET, SOCK_STREAM, 0);
  if (listen_sd < 0)
  {
    perror("socket() failed");
    exit(-1);
  }

  /*************************************************************/
  /* Allow socket descriptor to be reuseable */
  /*************************************************************/
  rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *) &on,
      sizeof(on));
  if (rc < 0)
  {
    perror("setsockopt() failed");
    close(listen_sd);
    exit(-1);
  }

  /*************************************************************/
  /* Set socket to be non-blocking. All of the sockets for */
  /* the incoming connections will also be non-blocking since */
  /* they will inherit that state from the listening socket. */
  /*************************************************************/
  rc = ioctl(listen_sd, FIONBIO, (char *) &on);
  if (rc < 0)
  {
    perror("ioctl() failed");
    close(listen_sd);
    exit(-1);
  }

  /*************************************************************/
  /* Bind the socket */
  /*************************************************************/
  memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl(INADDR_ANY);
  addr.sin_port = htons(scheduler_queue->portInt);
  rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr));
  if (rc < 0)
  {
    perror("bind() failed");
    close(listen_sd);
    exit(-1);
  }

  /*************************************************************/
  /* Set the listen back log */
  /*************************************************************/
  rc = listen(listen_sd, 32);
  if (rc < 0)
  {
    perror("listen() failed");
    close(listen_sd);
    exit(-1);
  }

  /*************************************************************/
  /* Initialize the master fd_set */
  /*************************************************************/
  FD_ZERO(&master_set);
  max_sd = listen_sd;
  FD_SET(listen_sd, &master_set);

  do
  {
    /**********************************************************/
    /* Copy the master fd_set over to the working fd_set. */
    /**********************************************************/
    memcpy(&working_set, &master_set, sizeof(master_set));

    /**********************************************************/
    /* Call select() and wait 5 minutes for it to complete. */
    /**********************************************************/
    timeout.tv_sec = 0;
    timeout.tv_usec = 0;

    rc = select(FD_SETSIZE, &working_set, NULL, NULL, &timeout);

    /**********************************************************/
    /* Check to see if the select call failed. */
    /**********************************************************/
    if (rc < 0)
    {
      perror(" select() failed");
      break;
    }

    /**********************************************************/
    /* Check to see if the 5 minute time out expired. */
    /**********************************************************/
    if (rc == 0)
    {
      planificar(scheduler_queue);
    }
    else
    {
      desc_ready = rc;
      for (j = 0; j <= max_sd && desc_ready > 0; ++j)
      {
        /*******************************************************/
        /* Check to see if this descriptor is ready */
        /*******************************************************/
        if (FD_ISSET(j, &working_set))
        {
          /****************************************************/
          /* A descriptor was found that was readable - one */
          /* less has to be looked for. This is being done */
          /* so that we can stop looking at the working set */
          /* once we have found all of the descriptors that */
          /* were ready. */
          /****************************************************/
          desc_ready -= 1;

          /****************************************************/
          /* Check to see if this is the listening socket */
          /****************************************************/
          if (j == listen_sd)
          {
            printf(" Listening socket is readable\n");
            /*************************************************/
            /* Accept all incoming connections that are */
            /* queued up on the listening socket before we */
            /* loop back and call select again. */
            /*************************************************/
            do
            {
              /**********************************************/
              /* Accept each incoming connection. If */
              /* accept fails with EWOULDBLOCK, then we */
              /* have accepted all of them. Any other */
              /* failure on accept will cause us to end the */
              /* server. */
              /**********************************************/
              new_sd = accept(listen_sd, NULL, NULL);
              if (new_sd < 0)
              {
                if (errno != EWOULDBLOCK)
                {
                  perror(" accept() failed");
                  end_server = TRUE;
                }
                break;
              }

              /**********************************************/
              /* Add the new incoming connection to the */
              /* master read set */
              /**********************************************/
              printf(" New incoming connection - %d\n", new_sd);
              FD_SET(new_sd, &master_set);
              queue_push(scheduler_queue->character_queue, new_sd);
              if (new_sd > max_sd)
                max_sd = new_sd;

              /**********************************************/
              /* Loop back up and accept another incoming */
              /* connection */
              /**********************************************/
            } while (new_sd != -1);
          }

          /****************************************************/
          /* This is not the listening socket, therefore an */
          /* existing connection must be readable */
          /****************************************************/
        }
      } /* End of if (FD_ISSET(i, &working_set)) */
    } /* End of loop through selectable descriptors */

  } while (end_server == FALSE);

}

非常感谢!

0 个答案:

没有答案