【发布时间】:2014-08-16 10:29:09
【问题描述】:
我有一个将消息接收到套接字的服务器,并且对于接收到的每条消息,执行一个 fork exec。这部分似乎工作正常。
但我需要在非阻塞模式下执行此操作,因此我创建了一个处理程序以使用 waitpid() 正确清理所有已终止的子进程(如论坛中的许多主题中所述)。
问题是这个处理程序对我的pselect 命令生成了一个中断的系统调用,它会停止程序并显示以下消息:"select(): Interrupted system call"
我在“防止竞争条件”之类的论坛上找到了一些关于这个问题的解释,所以我尝试使用sigprocmask() 来阻止几个信号,但没有成功。
我确信这是一个微不足道的问题,但这是我第一次使用这种程序。
我需要一些帮助。 提前致谢。
这是程序:
void
clean_up_child_process (int signal_number)
{
pid_t p;
int status;
while (1)
{
p = waitpid (-1, &status, WNOHANG);
if (p == -1)
{
if (errno == EINTR)
{
continue;
}
break;
}
else if (p == 0)
{
break;
}
}
}
static void
app (void)
{
SOCKET sock;
char commande[BUF_SIZE];
char res_cmd[BUF_SIZE];
int max;
int n;
sock = init_connection ();
max = sock;
fd_set rdfs;
sigemptyset (&sigmask);
sigaddset (&sigmask, SIGCHLD);
sigaddset (&sigmask, SIGINT);
sigaddset (&sigmask, SIGTSTP);
sigaddset (&sigmask, SIGTERM);
sigprocmask (SIG_BLOCK, &sigmask, NULL);
struct sigaction sigchld_action;
memset (&sigchld_action, 0, sizeof (sigchld_action));
sigchld_action.sa_handler = &clean_up_child_process;
sigaction (SIGCHLD, &sigchld_action, NULL);
while (1)
{
int i = 0;
FD_ZERO (&rdfs);
/* add STDIN_FILENO */
FD_SET (STDIN_FILENO, &rdfs);
/* add the connection socket */
FD_SET (sock, &rdfs);
sigemptyset (&empty_mask);
if (pselect (max + 1, &rdfs, NULL, NULL, NULL, &empty_mask) == -1)
if (errno != EINTR)
{
perror ("select()");
exit (errno);
}
if (FD_ISSET (STDIN_FILENO, &rdfs))
{
/* stop process when type on keyboard */
// break; must be disable to avoid bad exits
}
else if (FD_ISSET (sock, &rdfs))
{
/* new client */
SOCKADDR_IN csin = { 0 };
size_t sinsize = sizeof csin;
int csock = accept (sock, (SOCKADDR *) & csin, &sinsize);
if (csock == SOCKET_ERROR)
{
perror ("accept()");
continue;
}
if ((n = recv (csock, commande, BUF_SIZE - 1, 0)) < 0)
{
perror ("recv(commande)");
n = 0;
continue;
}
commande[n] = 0;
if ((n = fork ()) == -1)
perror ("fork()");
else if (n == 0)
{
close (STDOUT_FILENO);
dup (csock);
close (STDERR_FILENO);
dup (csock);
execlp (commande, commande, 0);
}
else
{
closesocket (csock);
}
}
}
end_connection (sock);
}
【问题讨论】:
-
signal_number 似乎没有在您的 clean_up_child_process 方法中使用?
-
我的理解是:Signal is given by sigaction : sigaction (SIGCHLD, &sigchld_action, NULL);你在这里设置句柄函数:sigchld_action.sa_handler = &clean_up_child_process;在你使用 sigaction 之后。
-
当
pselect()返回-1时,如果errno == EINTR则不要exit()- 而是循环返回并重新启动pselect()调用。这是很正常的行为。 -
您好,Paul,非常感谢您的建议,它现在可以正常工作了。我只需要更改处理函数(直接更新到帖子中)。我不知道为什么第一次连接后旧的挂起。现在好啦。我不知道为什么如果我用 FD_ISSET(STDIN_FILENO, &rdfs) 管理键盘,如果我不按键盘,程序会在第一个连接事件后直接退出。这并不重要,因为我不会在真正的服务器中使用它。这很奇怪(对我来说:-))
标签: c select fork zombie-process waitpid