zoukankan      html  css  js  c++  java
  • 在linux系统中实现各项监控的关键技术(2)--内核态与用户态进程之间的通信netlink

    Netlink 是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的 socket API 就可以使用 netlink 提供的强大功能,内核态需要使用专门的内核 API 来使用netlink。如果需要在用户态捕捉到一些内核的信息,就可以通过netlink的机制,将消息从内核发送给用户态。比如,在ext3文件系统处理的ext3_handle_error,以及ext3_abort处挂个函数,函数中实现netlink机制,那么当文件系统异常后,走入ext3_abort,以及ext3_handle_error函数时,就会进入钩子函数,再将信息通过netlink发送到用户态。

    Netlink 相对于系统调用,ioctl 以及 /proc 文件系统而言具有以下优点:

    1,为了使用 netlink,用户仅需要在 include/linux/netlink.h 中增加一个新类型的 netlink 协议定义即可, 如 #define NETLINK_MYTEST 17 然后,内核和用户态应用就可以立即通过 socket API 使用该 netlink 协议类型进行数据交换。但系统调用需要增加新的系统调用,ioctl 则需要增加设备或文件, 那需要不少代码,proc文件系统则需要在/proc下添加新的文件或目录,那将使本来就混乱的/proc更加混乱。

    2. netlink是一种异步通信机制,在内核与用户态应用之间传递的消息保存在socket缓存队列中,发送消息只是把消息保存在接收者的socket的接 收队列,而不需要等待接收者收到消息,但系统调用与ioctl 则是同步通信机制,如果传递的数据太长,将影响调度粒度。

    3.使用 netlink 的内核部分可以采用模块的方式实现,使用 netlink 的应用部分和内核部分没有编译时依赖,但系统调用就有依赖,而且新的系统调用的实现必须静态地连接到内核中,它无法在模块中实现,使用新系统调用的应用在编译时需要依赖内核。

    4.netlink支持多播,内核模块或应用可以把消息多播给一个netlink组,属于该neilink组的任何内核模块或应用都能接收到该消息,内核事件向用户态的通知机制就使用了这一特性,任何对内核事件感兴趣的应用都能收到该子系统发送的内核事件,在后面的文章中将介绍这一机制的使用。

    5.内核可以使用netlink首先发起会话,但系统调用和 ioctl 只能由用户应用发起调用。

    6.netlink使用标准的 socket API,因此很容易使用,但系统调用和 ioctl则需要专门的培训才能使用。

    用户态使用 netlink

    用户态应用使用标准的socket APIs, socket(), bind(), sendmsg(), recvmsg() 和 close() 就能很容易地使用 netlink socket,查询手册页可以了解这些函数的使用细节,本文只是讲解使用 netlink 的用户应该如何使用这些函数。注意,使用 netlink 的应用必须包含头文件 linux/netlink.h。当然 socket 需要的头文件也必不可少,sys/socket.h。

        struct nlmsghdr *nlh = NULL;
        struct sockaddr_nl local;
        struct msghdr msg;
        struct iovec iov;
        struct test_msg *testmsg = NULL;
    
        sockfd = socket(PF_NETLINK, (int)SOCK_RAW | SOCK_CLOEXEC, NETLINK_MYTEST);
        if (sockfd < 0) {
        }
    
        memset(&local, 0, sizeof(local));
        local.nl_family = PF_NETLINK;
        local.nl_pid = getpid();
        local.nl_groups = FS_ERROR_GRP_EXT3;
    
        if (bind(sockfd, (struct sockaddr*)&local, sizeof(local))) {
        }
    
        nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(sizeof(struct test_msg)));
        if (!nlh) {
        }
        
        memset(nlh, 0, NLMSG_SPACE(sizeof(struct test_msg)));
        nlh->nlmsg_len = NLMSG_SPACE(sizeof(struct test_msg));
        nlh->nlmsg_pid = pthread_self() << 16 | getpid();
        nlh->nlmsg_flags = 0;
    
        memset(&iov, 0, sizeof(iov));  
        iov.iov_base = (void*)nlh;
        iov.iov_len = nlh->nlmsg_len;    
    
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
    
        if (recvmsg(sockfd, &msg, 0) < 0) {
        }
    
        testmsg = (struct test_msg *)NLMSG_DATA(nlh);

    具体解释可以参见:

    https://www.cnblogs.com/iceocean/articles/1594195.html

  • 相关阅读:
    Mysql支持的数据类型
    JavaScript 原型中的哲学思想
    99%的人都理解错了HTTP中GET与POST的区别
    Let's Encrypt,站点加密之旅
    说说cglib动态代理
    说说Java代理模式
    RESTful API 编写指南
    RESTful 架构风格概述
    Centos 6 搭建安装 Gitlab
    超详细的阿里字节Spring面试技术点总结(建议收藏)
  • 原文地址:https://www.cnblogs.com/xingmuxin/p/9300717.html
Copyright © 2011-2022 走看看