sigpipe c server/client - 程序在哪里重新启动?

Posted

技术标签:

【中文标题】sigpipe c server/client - 程序在哪里重新启动?【英文标题】:sigpipe c server/client - where does the program restart? 【发布时间】:2014-10-22 05:40:12 【问题描述】:

我有一个客户端/服务器程序,现在我想处理信号。当客户端关闭连接时(例如,如果我关闭终端),服务器必须处理 SIGPIPE,对吗?我想实现这样的东西。有可能吗?

server.c:

void function()
   printf("...");
   read(socket,buff,size);
   //IF THE CLIENT CLOSES, THE SERVER RECEIVES A SIGPIPE
   ...the resting part of the scheduled code should be ignored if sigpipe is received, and the program should begin from where I wrote on the handler of the sigpipe...
   printf("not working"); //this should be ignored, but it's printed 2 times immediatly, and when I've finished the actions indicated in the function by the handler, it prints it another time, because the program counter restarts from here...


void sigpipehandler()
   close(socket);
   main(); //I'd like that the program restarts from the main when I've received a SIGPIPE. It restarts from the main, but only after having printed "not working" two times...


int main()
   sigPipe.sa_sigaction = &sigpipehandler;
   sigPipe.sa_flags = SA_SIGINFO;
   sigaction(SIGPIPE, &sigpipehandler, NULL);
   ...code...

【问题讨论】:

当你写到一个封闭的管道时你会得到 SIGPIPE;当您从封闭管道读取时,您会得到 EOF(读取零字节)。 @JonathanLeffler 感谢您的回复。因此,如果我在示例中将读取更改为写入。我该如何处理 SIGPIPE,就像解释的那样? 最简单的就是忽略SIGPIPE,然后监听write()的返回值。如果它返回 -1 并且 errno 设置为 EINTR,您可能会怀疑您有一个 SIGPIPE,特别是如果您没有任何其他信号处理集。当然,无论如何,您应该查看来自write()read() 的返回值。您不想从信号处理程序中递归调用 main()。您可以在main() 中编写一个循环,并让信号处理程序设置一个您在循环中测试的标志。根据标准 C,您在信号处理程序中唯一能做的就是修改变量或退出。 【参考方案1】:

将 cmets 转换为答案。

请注意,只有当您写入没有进程且管道的读取端打开的管道时,您才会获得 SIGPIPE。当您从没有进程且管道的写入端打开的管道中读取时,您会得到 EOF(读取零字节)。

所以,如果我在示例中将read() 更改为write()。如何处理 SIGPIPE?

最简单的就是忽略SIGPIPE(signal(SIGPIPE, SIG_IGN)),然后监听write()的返回值。如果它返回 -1 并且 errno 设置为 EINTR,您可以假设您被某些信号打断,而且很可能是 SIGPIPE,尤其是在您没有任何其他信号处理集的情况下。当然,无论如何,您应该查看来自 write()read() 的返回值。

或者,如果你想要一个显式的 SIGPIPE 处理程序,那么你肯定不想从你的信号处理程序递归调用main()。您可以在main() 中编写一个循环,并让信号处理程序设置一个您在循环中测试的标志。根据标准 C,您在信号处理程序中唯一能做的就是修改变量或退出。

static volatile sigatomic_t sig_recvd = 0;
static int sock_fd = -1;

void sigpipehandler(int signum)

   close(sock_fd);
   sock_fd = -1;
   sig_recvd = signum;


int main(void)

    sigPipe.sa_sigaction = &sigpipehandler;
    sigPipe.sa_flags = SA_SIGINFO;
    sigemptyset(&sigPipe.sa_mask);
    sigaction(SIGPIPE, &sigpipehandler, NULL);

    int done = 0;

    while (!done)
    
        if (sock_fd == -1)
        
            if (sig_recvd != 0)
            
                ...report signal received...
                sig_recvd = 0;
            
            ...(re)open socket on sock_fd...
        
        ...code as before - sets done = 1 when loop should terminate...
    
    return 0;

请注意,将变量命名为与系统调用相同(代码中的socket)是如履薄冰;因此,我将其重命名为sock_fd。一个名为 socket 的全局变量将是一个非常糟糕的主意。

【讨论】:

以上是关于sigpipe c server/client - 程序在哪里重新启动?的主要内容,如果未能解决你的问题,请参考以下文章

如何处理生成它的对象内部的 SIGPIPE 错误?

Eclipse CDT:线程在调试模式下获取 SIGPIPE

c udp server client demo --待调试

c tcp sockt server client -- demo

如果前端 Tomcat 被杀死,C++ 服务器将终止。错误“收到未捕获的信号 [13] - SIGPIPE”

为啥存在 SIGPIPE?