我在处理僵尸进程时遇到了一些问题。我写了一个简单的服务器,它可以创建玩家之间的tic tac toe比赛。我正在使用select()在多个连接的客户端之间进行多路复用。只要有两个客户端,服务器就会分叉另一个执行匹配仲裁程序的进程。使用select()进行多路复用时等待子进程
问题是select()块。因此,如果有一个匹配仲裁程序作为子进程运行并退出,则由于select()被阻塞,所以如果没有传入连接,父进程将永远不会等待该子进程。
我有我的代码在这里,道歉,因为它很混乱。
while(1) {
if (terminate)
terminate_program();
FD_ZERO(&rset);
FD_SET(tcp_listenfd, &rset);
FD_SET(udpfd, &rset);
maxfd = max(tcp_listenfd, udpfd);
/* add child connections to set */
for (i = 0; i < MAXCLIENTS; i++) {
sd = tcp_confd_lst[i];
if (sd > 0)
FD_SET(sd, &rset);
if (sd > maxfd)
maxfd = sd;
}
/* Here select blocks */
if ((nready = select(maxfd + 1, &rset, NULL, NULL, NULL)) < 0) {
if (errno == EINTR)
continue;
else
perror("select error");
}
/* Handles incoming TCP connections */
if (FD_ISSET(tcp_listenfd, &rset)) {
len = sizeof(cliaddr);
if ((new_confd = accept(tcp_listenfd, (struct sockaddr *) &cliaddr, &len)) < 0) {
perror("accept");
exit(1);
}
/* Send connection message asking for handle */
writen(new_confd, handle_msg, strlen(handle_msg));
/* adds new_confd to array of connected fd's */
for (i = 0; i < MAXCLIENTS; i++) {
if (tcp_confd_lst[i] == 0) {
tcp_confd_lst[i] = new_confd;
break;
}
}
}
/* Handles incoming UDP connections */
if (FD_ISSET(udpfd, &rset)) {
}
/* Handles receiving client handles */
/* If client disconnects without entering their handle, their values in the arrays will be set to 0 and can be reused. */
for (i = 0; i < MAXCLIENTS; i++) {
sd = tcp_confd_lst[i];
if (FD_ISSET(sd, &rset)) {
if ((valread = read(sd, confd_handle, MAXHANDLESZ)) == 0) {
printf("Someone disconnected: %s\n", usr_handles[i]);
close(sd);
tcp_confd_lst[i] = 0;
usr_in_game[i] = 0;
} else {
confd_handle[valread] = '\0';
printf("%s\n", confd_handle); /* For testing */
fflush(stdout);
strncpy(usr_handles[i], confd_handle, sizeof(usr_handles[i]));
for (j = i - 1; j >= 0; j--) {
if (tcp_confd_lst[j] != 0 && usr_in_game[j] == 0) {
usr_in_game[i] = 1; usr_in_game[j] = 1;
if ((child_pid = fork()) == 0) {
close(tcp_listenfd);
snprintf(fd_args[0], sizeof(fd_args[0]), "%d", tcp_confd_lst[i]);
snprintf(fd_args[1], sizeof(fd_args[1]), "%d", tcp_confd_lst[j]);
execl("nim_match_server", "nim_match_server", usr_handles[i], fd_args[0], usr_handles[j], fd_args[1], (char *) 0);
}
close(tcp_confd_lst[i]); close(tcp_confd_lst[j]);
tcp_confd_lst[i] = 0; tcp_confd_lst[j] = 0;
usr_in_game[i] = 0; usr_in_game[j] = 0;
}
}
}
}
}
}
是否有一种方法,即使在select()阻塞时也允许等待运行?由于它们是异步的,所以最好不要处理信号
编辑:其实,我发现select有一个timeval数据结构,我们可以指定超时。将使用这是一个好主意?
在select()语句中使用timeout参数(最后一个参数)。然后select后的下一条指令应该是检查发生的超时。检查超时的一种方法是检查输入fd_set是否全为零(或检查目标fd条目是否为零) – user3629249 2015-03-25 05:21:26
否!不应只使用超时参数并检查是否发生超时。如果超时为2秒,程序每秒接收一块数据,那么超时不会发生。当你从select返回时,你应该在所有情况下运行定时代码,而不仅仅是在超时情况下。如果你想让代码每秒运行一次,你可以存储它的最后执行时间,然后检查cur_time() - last_exec_time是否大于一秒。 – juhist 2015-03-25 09:04:45