我有一个需要执行以下操作的应用程序:
我受限于我不能使用线程,只能使用进程。我也无法等待reconnect()返回的结果。
到目前为止,我有这样的设计:
int main(int argc, char **argv)
{
/* do main loop work, if disconnected, call reconnect() & continue doing work */
}
void reconnect()
{
pid = fork();
if (pid >= 0) {
/*Successful fork*/
if (pid == 0) {
rv = attempt_reconnect;
if (rv == 0) {
/*Notify sig_child Success*/
exit(0);
} else {
/*Notify sig_child Fail*/
exit(1);
}
}
}
}
void sig_child(int signum)
{
if(fork returned success) {
set flag to continue network stuff
}
else {
alarm(20);
}
}
void sig_alarm(int signo)
{
/*Received alarm, trying to reconnect...*/
reconnect();
}
非常感谢任何帮助!
修改
我想我的解决方案是here。它允许我创建具有单独ID的计时器,然后识别哪个已经发信号通知程序
答案 0 :(得分:2)
使用以下代码I found here,我已经实现了(我认为)我想要做的事情。
它允许分别使用函数“makeTtimer”和“timerHandler”创建和处理多个timer_t对象:
timer_t reconnect_timer_id;
timer_t timeout_timer_id;
int main(int argc, char **argv)
{
/* do main loop work */
if(disconnected()) {
/*IF TIMEOUT SET, SKIP, IF OK, RESET*/
if(timeout_set != 1) {
"Schedule Alarm"
makeTimer("Timeout Timer", &timeout_timer_id, 600,0);
timeout_set = 1;
} else {
"Timeout alarm already set..";
}
reconnect();
}
}
void reconnect()
{
pid = fork();
if (pid >= 0) {
/*Successful fork*/
if (pid == 0) {
rv = attempt_reconnect;
if (rv == 0) {
/*Notify sig_child Success*/
exit(0);
} else {
/*Notify sig_child Fail*/
exit(1);
}
}
}
}
void sig_child(int signum)
{
if(fork returned success) {
set flag to continue network stuff
}
else {
"Reconnect fail, retrying in 20 seconds...";
makeTimer("Reconnect Timer", &reconnect_timer_id, 20,0);
}
}
static void
timerHandler( int sig, siginfo_t *si, void *uc )
{
timer_t *tidp;
tidp = si->si_value.sival_ptr;
if ( *tidp == timeout_timer_id ) {
if(state != STATE_CONNECTED) {
"Timeout alarm received, not connected to server, exiting..."
exit(0);
} else {
"Timeout alarm received, connected to server, continuing..."
timeout_set = 0;
}
} else if ( *tidp == reconnect_timer_id ) {
"Reconnect alarm received, retrying...";
reconnect();
}
}
static int
makeTimer( char *name, timer_t *timerID, int expireSeconds, int intervalSeconds )
{
struct sigevent te;
struct itimerspec its;
struct sigaction sa;
int sigNo = SIGRTMIN;
/* Set up signal handler. */
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = timerHandler;
sigemptyset(&sa.sa_mask);
if (sigaction(sigNo, &sa, NULL) == -1) {
"Failed to setup signal handling for" *name;
return(-1);
}
/* Set and enable alarm */
te.sigev_notify = SIGEV_SIGNAL;
te.sigev_signo = sigNo;
te.sigev_value.sival_ptr = timerID;
timer_create(CLOCK_REALTIME, &te, timerID);
its.it_interval.tv_sec = intervalSeconds;
its.it_interval.tv_nsec =0;
its.it_value.tv_sec = expireSeconds;
its.it_value.tv_nsec = 0;
timer_settime(*timerID, 0, &its, NULL);
return(0);
}
答案 1 :(得分:1)
一个想法可能不是使用alarm( )
,而是创建定时器作为kill
sleep()
void timer( int nsec, int signum )
{
pid_t pid = getpid();
if( fork() > 0 ) {
sleep( nsec );
kill( pid, signum );
exit( 0 );
}
}
之后具有两个不同信号的主要过程的子过程:
void sig_timer( int signum )
{
if( signum == SIGUSR1 ) {
// reconnect
} else if( signumm == SIGUSR2 ) {
if( !reconnected )
exit( 11 );
}
}
通过使用两个不同的信号(例如,用于短定时器的SIGUSR1和用于长定时器的SIGUSR2),您可以拥有这样的信号处理器:
{{1}}
答案 2 :(得分:1)
您只能通过在主循环中轮询它们来使用警报和标志来执行此操作。在主循环中选择断开事件后,您可以设置20秒的警报并使用标志处理处理程序或主循环中的重新连接。继续设置20秒的警报,直到您重新连接或5五分钟到期。如果20秒警报发生15次,您可以在警报处理程序中再次检查此项。 现在如果5分钟到期,则可以重置警报(0)并通知主循环关闭。 这样的事情。
int disconnect_event = 0;
int reconnect_try = 1;
int five_minutes = 0;
int shutdown = 0;
void alarm_handler(int signum)
{
if(five_minutes == 15)
{
alarm(0);
shutdown = 1;
}
else
{
reconnect_try = 1;
alarm(20);
five_minutes++
}
}
int main(int argc, char*argv[])
{
signal(SIGALRM, alarm_handler);
while(1)
{
if(disconnect_event && reconnect_try)
{
if(reconnect() == 0)
{
alarm(20);
reconnect_try = 0;
}
else
{
disconnect_event = 0;
reconnect_try = 1;
}
}
if(shutdown)
{
disconnect_event = 0;
reconnect_try = 0;
alarm(0)
}
}
}
答案 3 :(得分:0)
从问题中不清楚应用程序是否需要在connect()正在进行时继续运行(1),以及(2)当它处于“短暂等待”时。
如果不需要在这些时段中的任何一个中运行,那么当您需要使用长计时器时,将长计时器到期的绝对时间放入某个变量,如下:
time_t run_until = time(NULL) + 60;
并且在每次不成功的connect()之后检查当前时间是否大于run_until:
if (connect_rc) {if (time(NULL) > run_until) shutdown(); else reconnect();}
您将获得上述逻辑,而无需任何进程或线程。
如果您需要在connect()正在进行时继续运行,和/或在重新连接之前处于短暂暂停状态,则可以使用非阻塞套接字。怎么做是一个冗长的讲座问题;本质上,你围绕select()或poll()安排你的主循环。这些函数允许您等待一组事件中的一个发生,事件是:完成后台connect(),或者到达数据准备好recv()/ read(),或者重要的是,计时器到期。这种方法也不涉及线程或进程。