我正在做一个多客户端服务器,它接受连接,分叉,并提供与子进程的连接,以便它可以处理它。它是一个多客户端服务器,因此它有多个孩子。
主要过程是无限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);
}
}
}
因此,随机地,当我关闭连接时,select unblock就好像“sockifd”被修改了一样,但事实并非如此。不知道为什么这样做。
答案 0 :(得分:4)
您的代码中有一个问题是您没有检查select
的返回值。
如果select
被信号中断(-1
返回errno = EINTR
,例如SIGCHLD
,如果其中一个孩子死亡),那么{{1}的内容未定义,因此不能被读取。 (例如,参见select
的Linux手册页。)
因此,请检查&readfds
的返回值,如果出现select
之类的临时错误,请在不经过&readfds
处理的情况下直接循环回来。
答案 1 :(得分:1)
非常感谢Mat的评论,实际上,有一个中断是解锁选择,我用它来解决它(当然还有更多的方法):
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
我希望这对有同样问题的人有用=)
答案 2 :(得分:0)
当子关闭套接字连接时,select将解除阻塞,“recv”将返回0.因此,您应该始终检查“recv”函数的返回值,以确定连接是否已关闭。