2011-07-21 53 views
2

我正在做一个多客户端服务器,它接受一个连接,分叉并将连接提供给孩子,以便它可以处理它。这是一个多客户端服务器,因此它有多个孩子。关闭套接字时选择的问题

主要过程是在无限的while,这使得select找出是否有新的传入连接或如果一个孩子正在尝试通信。

当我关闭一个客户端(它连接到主服务器的一个儿子)时出现问题: 它随机发生客户端连接关闭,并且select取消阻塞,因为据说内部套接字(处理儿童和主服务器之间的传入连接)进行了修改,但就我而言,事实并非如此。 实际发生的事情是客户关闭了连接,并且孩子刚刚死亡。

任何人都可以给我一个这里发生的事情的线索吗?我很迷茫。

这是无限循环的主服务器的代码:

while (1) { 
    /*inicializo variables para el select*/ 
    sflag = 0; 
    FD_ZERO(&readfds); 
    FD_SET(sockfd, &readfds); 
    FD_SET(sockifd,&readfds); 
    max = (sockfd > sockifd) ? sockfd : sockifd; 
    for(aux = isockets; aux != NULL; aux = aux -> next){ 
     FD_SET(aux -> sd, &readfds); 
     max = (max > aux -> sd) ? max : aux -> sd; 
    } 

    printf("pre-select\n"); 
    select(max + 1, &readfds, NULL, NULL, NULL); 
    /*checkeo si salio por actividad en un socket interno*/ 
    for (aux = isockets; aux != NULL; aux = aux -> next){ 
     if (FD_ISSET(aux -> sd, &readfds)){ 
      printf("comunicacion con el socket: %d\n", aux -> sd); 
      sflag = 1; 
      actsocket = aux -> sd; 
      break; 
     } 
    } 
    if (sflag == 1){//mensaje de un hijo 
     n = recv(actsocket, buffer, sizeof(buffer), 0); 
     if (n == 0) { 
      printf("conexion cerrada con el socket interno: %d\n", actsocket); 
      close(actsocket); 
      isockets = free_sock(isockets, actsocket); 
      printf("isockets: %p\n", isockets); 
     } 
     else if(n < 0) error ("ERROR en comunicacion interna"); 
     else printf("mensaje del boludon: %s\n", buffer); 
    } 
    else if (FD_ISSET(sockifd, &readfds)){// un hijo inicia conexion interna 
     printf("antes de accpet interno\n"); 
     newisockfd = accept(sockifd, (struct sockaddr *) &ucli_addr, &uclilen); 
     printf("nueva conexion interna, socketfd: %d\n", newisockfd); 
     isockets = add_socket(isockets,newisockfd, 0); 
     recorre(isockets); 
     if (newisockfd < 0) error ("ERROR en accept unix, padre"); 
    } 
    else if (FD_ISSET (sockfd, &readfds)){/*conexion entrante*/ 
     printf("conexion entrante\n"); 
     newsockfd = accept(sockfd,(struct sockaddr *) &cli_addr, &clilen); 
      if (newsockfd < 0) error("ERROR on accept"); 
      pid = fork(); 

     if (pid < 0) error("ERROR on fork"); 
      if (pid == 0){//hijo 
        close(sockfd); 
      dostuff(newsockfd, path, tm,fd[0]); 
        exit(0); 

      } 
      else { //padre 
      printf("conexion aceptada, pid hijo %d\n", pid); 
      close(newsockfd); 
     } 
    } 
    } 

所以,随机,当我关闭连接时,选择解锁仿佛“sockifd”进行了修改,但它不是。不知道为什么要这样做。

回答

4

你的代码有一件事是错误的,那就是你没有检查返回值select

如果select通过信号中断(返回-1errno = EINTR,例如SIGCHLD如果一个孩子死亡),则&readfds内容是不确定的,并且因此不能被读出。 (见例如用于select Linux手册页。)

如果select所以检查返回值,环右后卫它不用经过&readfds处理,如果有喜欢EINTR临时错误。

0

当孩子关闭套接字连接时,select将取消阻塞,“recv”将返回0.因此,应始终检查“recv”函数的返回值,以确定连接是否已关闭。

+1

看看代码:他呢。 – Mat

1

非常感谢这句话垫,它实际上是,有说是疏通选择的中断,我这个解决它(有更多的方式来做到这一点,当然):

repeat_select: 
if((err = select (max + 1, &readfds, NULL, NULL, NULL)) < 0) 
    if (errno == EINTR) //a signal has interrupted the select, so I restarted it 
     goto repeat_select; 
    else 
     //another error, handle it as you want 

我希望这将是有用的人有相同的问题=)