草庐IT

c++ - SIGINT 信号在写入管道期间被丢弃

coder 2024-02-05 原文

我有一个程序使用 pcap_dump 函数将使用 libpcap 收集的 pcap 数据转储到标准输出,标准输出作为文件 *。需要对 SIGINT 进行一些清理,所以我使用 sigaction() 来处理它。这在从 shell 执行时效果很好。

但是,这个程序本来是要被另一个程序调用的,好像不行。这个“调用者”程序先调用一个 pipe(),然后调用一个 fork(),然后子进程的 stdout 文件描述符被关闭,并替换为管道的写入端。最后在子进程中执行前述的pcap程序。这样pcap数据就通过管道写入了调用程序。这也很好用。但是,当我向正在写入管道的子进程发送一个 SIGINT 时(好吧,pcap 程序认为它正在写入 stdout,但它的文件描述符已更改),信号似乎被丢弃,并且信号处理函数根本不会被调用。

这是为什么呢?如果我将 pcap 数据写入 stderr 或文件,则 SIGINT 永远不会被删除。仅在写入管道时。

下面是我们如何设置管道/分支/执行:

int fd[2];

//Create pipe
pipe(fd);

pid = fork(); //We forked a child

if(pid == 0){ //We are the child now

    close(1); //close child's stdout

    dup(fd[1]); //duplicate child's stdout to the write end of the pipe

    close( fd[0]); //close unused file descriptors
    close( fd[1]);

    //Load the new program
    execlp("./collectraw", "collectraw", NULL);

    perror("Exec");
    exit(127); //Should never get called but we leave it so the child
    //doesnt accidently keep executing
}
else{ //We are the parent

    //Set up the file descriptors
    close(fd[1]);
}

然后杀死我们使用的 child :

kill( pid, SIGINT);

在 child 中,我们的 pcap_loop() 的回调函数可以很简单:

void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet){
    write(1,"<pretend this is like a thousand zeros>",1000); //write to stdout, which is really a pipe
}

而且我们基本上总是会丢弃 SIGINT。顺便说一句,有很多数据包要捕获,所以可以很安全地假设它几乎总是在回调函数中。

但是如果我们改变从

write(1,... ); //write to stdout, which is really a pipe

write(2,...); //write to stderr, or writing to a file would work too

然后一切又变得平淡无奇了。

为什么我们的 SIGINT 在写入管道期间被丢弃?

感谢您的帮助。

编辑: child 的 SIGINT 处理程序根本没有被调用,但原因并不是 child 的问题,而是 parent 的问题。我曾经像这样杀死 child :

if( kill( pid, SIGINT) == -1){
    perror("Could not kill child");
}
close(pipefd);
fprintf(stdout, "Successfully killed child\n");

这曾经是我们的 SIGCHLD 处理程序:

void handlesigchild(int sig) {
    wait();

    printf("Cleaned up a child\n");
}

因此,如接受的答案中所述,立即关闭管道会导致我们的 child 在处理 SIGINT 之前使用 SIGPIPE 退出。我们刚刚将 close(pipefd) 移动到 SIGCHLD 处理程序,它现在可以工作了。

最佳答案

您没有显示足够多的代码来了解发生了什么。你应该总是尝试构造一个 SSCCE如果您希望人们能够对您的程序发表评论,请将其发布。

最佳猜测:您的 parent 在发送信号后退出,关闭管道的读取端。这会导致客户端在有机会处理 SIGINT 之前立即退出并发出 SIGPIPE。也尝试在 SIGPIPE 上进行清理,或者忽略 SIGPIPE。

关于c++ - SIGINT 信号在写入管道期间被丢弃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30519999/

有关c++ - SIGINT 信号在写入管道期间被丢弃的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  3. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  4. ruby - Ruby 是否使用 $stdout 来写入 puts 和 return 的输出? - 2

    我想知道Ruby用来在命令行打印这些东西的输出流:irb(main):001:0>a="test"=>"test"irb(main):002:0>putsatest=>nilirb(main):003:0>a=>"test"$stdout是否用于irb(main):002:0>和irb(main):003:0>?而且,在这两次调用之间,$stdout的值是否有任何变化?另外,有人能告诉我打印/写入这些内容的Ruby源代码吗? 最佳答案 是的。而且很容易向自己测试/证明。在命令行试试这个:ruby-e'puts"foo"'>test.

  5. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  6. Ruby:写入 stdin 并从 stdout 读取? - 2

    我正在编写一个ruby​​程序,它应该执行另一个程序,通过stdin向它传递值,从它的stdout读取响应,然后打印响应。这是我目前所拥有的。#!/usr/bin/envrubyrequire'open3'stdin,stdout,stderr=Open3.popen3('./MyProgram')stdin.puts"helloworld!"output=stdout.readerrors=stderr.readstdin.closestdout.closestderr.closeputs"Output:"puts"-------"putsoutputputs"\nErrors:"p

  7. Ruby -> 写入二维数组 - 2

    我正在处理http://prepwork.appacademy.io/mini-curriculum/array/中概述的数组问题我正在尝试创建函数my_transpose,它接受一个矩阵并返回其转置。我对写入二维数组感到很困惑!这是一个代码片段,突出了我的困惑。rows=[[0,1,2],[3,4,5],[6,7,8]]columns=Array.new(3,Array.new(3))putscolumns.to_s#Outputisa3x3arrayfilledwithnilcolumns[0][0]=0putscolumns.to_s#Outputis[[0,nil,nil],[

  8. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  9. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  10. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

随机推荐