首页 > 编程问答 >用 cgo 处理信号,go 不能处理信号

用 cgo 处理信号,go 不能处理信号

时间:2024-06-04 11:07:43浏览次数:26  
标签:go signals cgo

下面是我的 main.go

package main

/*
#include <stdio.h>;
#include <signal.h>;
#include <string.h>;
#include <stdlib.h>;
#include <unistd.h>;

// 用于存储旧操作的全局变量
struct sigaction old_action;

// 信号处理函数
void handler(int signum, siginfo_t *info, void *context) {
    printf("Received signal: %d\n", signum);
    printf("Sent by PID: %d\n", info->si_pid);
    printf("Signal code: %d\n", info->si_code);
    printf("User ID: %d\n", info->si_uid);
    if (info->si_pid != 0) {
        char proc_status_path[256];
        snprintf(proc_status_path, sizeof(proc_status_path), "/proc/%d/status", info->si_pid);
        FILE *fp = fopen(proc_status_path, "r");
        if (fp == NULL) {
            perror("fopen");
            返回;
        }
        char buffer[256];
        while (fgets(buffer, sizeof(buffer), fp)){
            printf("%s", buffer);
        }
        fclose(fp);
    }
}


// 设置信号处理的函数
void setup_signal_handler() {
    struct sigaction action;
    // 初始化动作结构
    memset(&action, 0, sizeof(action));
    sigfillset(&action.sa_mask); // 在处理程序执行期间阻断所有信号
    action.sa_sigaction = handler; // 设置信号处理函数
    action.sa_flags = SA_SIGINFO | SA_ONSTACK; // 设置标志

    // 设置 SIGTERM 信号处理函数
    if (sigaction(SIGTERM, &action, &old_action) < 0) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }
}
*/
import "C";
import "fmt";

func main() {
    C.setup_signal_handler()
    为 {
        fmt.Println("Sleeping..., waiting for signal")
        C.sleep(10)
    }
}
我正试图使用 C 语言来帮助我处理信号并打印出信号发送者的 pid。最初的 Go 软件包(syscall、os......等)并不提供此类信息。然而,当我运行上面的代码时,有两个进程启动了。一个是 go run . ,另一个是 signal ,也就是我的 go 软件包的名称。当我向 go run . 发送信号时,什么也不会发生,而向 signal 则会弹出信息。

我的理解是 implicity C 包会分叉另一个进程来运行这些 C 代码。我无法在我的 go 进程中应用 C 语言中的信号处理器。

我的目标是打印出发送到我的 go 进程的任何类型信号的信息。相关信息至少应包括 pid , ppid .也许还有其他更好的解决方案。

有关于 cgo 的文档吗?我找不到描述 cgo 软件包流程控制机制的文档。


[更新]

感谢 @kostix 和 @eik 的回答!我尝试了 go build 并在稍后运行二进制文件。看起来 C 信号处理器阻止了所有信号发送到 go 处理器。是否有可能同时允许 C 和 go 处理程序接收信号?

我尝试在 C 语言中再次启动,但 C 语言和 go 语言共享同一个 pid。仍在尝试下一个解决方案....


理解 cgo 与信号处理

你的理解是正确的,使用 cgo 调用 C 代码时,C 代码会运行在一个独立的线程中。这意味着 C 代码中的信号处理器会绑定到 C 线程,而不是 Go 主线程。这就是为什么你向 go run . 发送信号没有反应,而向 signal 发送信号却有反应的原因。

解决方案:使用管道在 C 和 Go 之间传递信息

由于 C 信号处理器无法直接与 Go 主线程交互,一种解决方案是使用管道在它们之间传递信息。

步骤:

  1. 在 Go 代码中创建一个管道:
reader, writer, err := os.Pipe()
if err != nil {
    // 处理错误
}
  1. 将管道写入端的文件描述符传递给 C 代码:
// ... 其他 C 代码
void setup_signal_handler(int pipeFd) {
    // ...
}

func main() {
    // ...
    C.setup_signal_handler(C.int(writer.Fd()))
    // ...
}
  1. 在 C 信号处理器中,将信号信息写入管道:
void handler(int signum, siginfo_t *info, void *context) {
    // ... 获取信号信息 ...

    // 将信息写入管道
    char message[256];
    snprintf(message, sizeof(message), "Signal: %d, PID: %d\n", signum, info->si_pid);
    write(pipeFd, message, strlen(message));
}
  1. 在 Go 代码中,从管道读取信息:
go func() {
    defer reader.Close()
    buf := make([]byte, 256)
    for {
        n, err := reader.Read(buf)
        if err != nil {
            // 处理错误
        }
        fmt.Printf("Received message: %s", string(buf[:n]))
    }
}()

注意事项:

  • 在 C 代码中,需要小心处理管道写入错误,确保不会阻塞信号处理。
  • 使用管道可能会引入额外的开销,需要根据实际情况进行权衡。

关于 cgo 文档

cgo 并没有独立的软件包,它更像是 Go 语言的一个特性。你可以在 Go 官方文档中找到关于 cgo 的详细介绍:

其他解决方案

  • 使用 Go 语言实现信号处理: 如果你只需要获取基本的信号信息,可以考虑完全使用 Go 语言实现信号处理。
  • 使用第三方库: 一些第三方库提供了更高级的信号处理功能,例如 github.com/sevoo/go-signal

希望这些信息能够帮助你解决问题!

标签:go,signals,cgo
From: 78569393

相关文章

  • Django + Vue 使用Nginx + uWsgi部署
    1.settings.py配置STATIC_ROOT=os.path.join(BASE_DIR,'static/dist')#导入前后端静态资源后更改即可DEBUG=True#为True不容易暴露项目信息,当然也不显示BUG信息ALLOWED_HOSTS=['*']STATIC_URL='/static/' 2.django端打包静态资源#会在static下生成[root@dsc1m......
  • PEnum_DistributionSystemElectricalCategory
    PEnum_DistributionSystemElectricalCategory  TypevaluesTypeDescriptionEXTRALOWVOLTAGENodescriptionavailable.HIGHVOLTAGENodescriptionavailable.LOWVOLTAGENodescriptionavailable.OTHERrequiredcategorynotonscaleNOTKN......
  • arcpy获取polygon内环
    当使用arcpy获取polygon几何的时候,不能像ao一样获取到内外环,只能获取到单个部件。而part返回的即是一个点组了。所以只能通过None对象进行分割,确定部件内的内外环。一个part内,只有一个外环,可以有多个内环。所以格式即为[ exteriorringpoint0, ..., exteriorringpointn, ......
  • 使用 Helmfile 插件进行 Argo CD 部署 - 未找到卷挂载
    我正试图在我的Rancherkubernetes集群中使用Helmfile插件设置ArgoCD部署,并遵循此参考文档。但是,我遇到了找不到卷挂载的问题。以下是我的设置细节:<代码Deployment.yaml:apiVersion:apps/v1类型:部署元数据:名称:argocd-repo-server命名空间:argocdspec:tem......
  • 生成式人工智能课程(1)——Goolge云生成式人工智能课程
    Google提供了两个生成式人工智能课程学习路径,官方称为LearningPath。地址为:分别是面向所有人的生成式人工智能入门(Beginner:IntroductiontoGenerativeAI),和面向开发者的人工智能(Advanced:GenerativeAIforDevelopers)1、生成式人工智能入门(Beginner:Introductiont......
  • 简单免杀绕过和利用上线的GoCS
    前言Goby可以快速准确的扫描资产,并直观呈现出来。同时经过上次EXP计划过后,PoC&EXP也增加了许多。在实战化漏洞扫描后,对于高危漏洞的利用,不仅仅只在whoami上,而是要进入后渗透阶段,那么对于Windows机器而言,上线CS是必不可少的操作,会让后渗透如鱼得水。此插件只运用了简......
  • golang使用阿里MQTT的通信记录
    背景:我们有业务场景就是手机App可以操作物连网设备,一年之中总会有一两次,手机无法操作设备,于是我们就需要将服务器重新启动就正常了,使用的是阿里MQTT服务。猜测:我一直怀疑,这个通信系统中的可能有BUG,消息丢失无法送达或者在传递过中发生了错乱无法正确收到消息。分析:仔细研究发现......
  • golang使用geoip2获取ip归属地
    gogetgithub.com/oschwald/geoip2-golang下载GeoIP2-City.mmdbhttps://dev.maxmind.com/geoip/geolite2-free-geolocation-datamain.gopackagemainimport( "fmt" "log" "net" "github.com/oschwald/geoip2-golang")......
  • mac虚拟定位软件:AnyGo for Mac 免激活版下载
    AnyGo软件是一款专业的虚拟定位工具,用户可以通过该软件模拟GPS定位,实现虚拟位置的设置。该软件可以应用于多种场景,比如在社交软件中设置虚拟位置、在游戏中改变位置等。用户可以根据自己的需求选择具体的虚拟位置,并且支持一键切换真实位置和虚拟位置。AnyGo软件操作简单,......
  • yolov8改进之嵌入Gold层
    #加载模型model=YOLO("yolov8n.yaml")  #从头开始构建新模型model=YOLO("yolov8n.pt")  #加载预训练模型(建议用于训练)#使用模型model.train(data="coco128.yaml",epochs=3)  #训练模型metrics=model.val()  #在验证集上评估模型性能results=model......