c / fork / signals / best practice在不同进程中关闭打开的套接字

时间:2011-05-19 09:56:32

标签: c fork signals

Hallo erveyone,

在我询问线程和分叉前两天。现在我最终使用了fork方法。 创建第二个进程,父进程和子进程执行不同的代码,但两者都以while循环结束,因为一个是通过套接字永远发送数据包而另一个正在套接字上永远监听。现在我希望它们在按下ctrl-c时清理,即两者都应该在返回之前关闭它们的开口插座。

我有三个文件,第一个,主文件创建进程。在第二个文件中写入父代码,在第三个文件中写入子代码。您可以在此处找到更多信息(代码段):c / interrupted system call / fork vs. thread

现在我的问题是,我必须在哪里放置信号处理程序,还是必须指定其中两个,每个进程一个?这似乎是一个简单的问题,但不是以某种方式对我而言。我尝试了不同的方法。但是只能让其中一个成功的人在返回前成功清理(我的英语很糟糕,因此很抱歉)。两者都必须做不同的事情,这对我来说是个问题,所以一个处理程序是不够的,对吧?

struct sigaction new_action;
new_action.sa_handler = termination_handler_1;
sigemptyset (&new_action.sa_mask);
new_action.sa_flags = 0;
sigaction(SIGINT, &new_action, NULL);

....more code here ... 

/* will run until crtl-c is pressed */
while(keep_going) {
    recvlen = recvfrom(sockfd_in, msg, itsGnMaxSduSize_MIB, 0, (struct sockaddr *) &incoming, &ilen);
    if(recvlen < 0) {
        perror("something went wrong / incoming\n");
        exit(1);
    }

    buflen = strlen(msg);
    sentlen = ath_sendto(sfd, &athinfo, &addrnwh, &nwh,  buflen, msg, &selpv2, &depv);

    if(sentlen == E_ERR) {
        perror("Failed to send network header packet.\n");
        exit(1);
    }
}

close(sockfd_in);
/* Close network header socket */
gnwh_close(sfd);
/* Terminate network header library */
gnwh_term();
printf("pc2wsu: signal received, closed all sockets and so on!\n");
return 0;
}


void termination_handler_1(wuint32 signum) {
    keep_going = 0;
}

正如您所看到的,在我的情况下处理信号只是改变循环条件“keep_going”。退出循环后,每个进程都应该清理。

提前感谢您的帮助。 nyyrikki

2 个答案:

答案 0 :(得分:2)

没有理由关闭插座。当进程退出时(作为SIGINT的默认操作),其所有文件描述符本身都是关闭的。除非你有其他必要的清理工作(比如将数据保存到磁盘),否则完全忘记处理信号。这几乎肯定是错误的。

答案 1 :(得分:1)

您的代码遇到竞争条件。你测试keep_going然后输入recvfrom,但它可能在那之间得到了信号。这是不太可能的,所以我们会忽略它。

听起来发送者和接收者是由同一个进程启动的,并且该进程是从shell启动的。如果您还没有做任何事情,它们将在同一个进程组中,当您点击^ C时,所有三个进程都将收到SIGINT。因此,如果你想运行清理代码,两个进程都处理SIGINT是最好的(注意关闭FD不是一个很好的理由......当进程退出时fds将被自动关闭)。如果它们是两者之间的TCP套接字,关闭一侧最终会导致另一方关闭(但对于发送方,直到它们再次尝试发送)。