zoukankan      html  css  js  c++  java
  • 【转】netlink socket编程实例

    【转】netlink socket编程实例 

    转自:http://blog.chinaunix.net/uid-14753126-id-2983915.html

    关于Netlink IPC方式的介绍,请参见http://blog.chinaunix.net/space.php?uid=14753126&do=blog&id=2978566
    本文通过一个编程实例来更深入地了解netlink。
    功能描述:
    1. 本实例包含2个部分:内核模块和用户程序
    2.用户程序通过netlink socket建立与kernel module连接,并向kernel module发送一条信息。
    3.内核在接收到用户的信息后,向用户程序发送一条确认信息。

    说明:对于不知如何编译内核模块以及用户程序的童鞋请google

    内核模块代码(test_netlink_kmodule.c):

    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/types.h>
    #include <linux/sched.h>
    #include <net/sock.h>
    #include <linux/netlink.h>
    
    #define NETLINK_TEST 17
    struct {
        __u32 pid;
    }user_process;
    
    static struct sock *netlinkfd = NULL;
    
    int send_to_user(char *info) //发送到用户空间
    {
        int size;
        struct sk_buff *skb;
        unsigned char *old_tail;
        struct nlmsghdr *nlh; //报文头
    
        int retval;
    
        size = NLMSG_SPACE(strlen(info)); //报文大小
        skb = alloc_skb(size, GFP_ATOMIC); //分配一个新的套接字缓存,使用GFP_ATOMIC标志进程不>会被置为睡眠
    
        //初始化一个netlink消息首部
        nlh = nlmsg_put(skb, 0, 0, 0, NLMSG_SPACE(strlen(info))-sizeof(struct nlmsghdr), 0); 
        old_tail = skb->tail;
        memcpy(NLMSG_DATA(nlh), info, strlen(info)); //填充数据区
        nlh->nlmsg_len = skb->tail - old_tail; //设置消息长度
    
        //设置控制字段
        NETLINK_CB(skb).pid = 0;
        NETLINK_CB(skb).dst_group = 0;
    
        printk(KERN_DEBUG "[kernel space] skb->data:%s
    ", (char *)NLMSG_DATA((struct nlmsghdr *)skb->data));
    
        //发送数据
        retval = netlink_unicast(netlinkfd, skb, user_process.pid, MSG_DONTWAIT);
        printk(KERN_DEBUG "[kernel space] netlink_unicast return: %d
    ", retval);
        return 0;
    }
    
    void kernel_receive(struct sk_buff *__skb) //内核从用户空间接收数据
    {
        struct sk_buff *skb;
        struct nlmsghdr *nlh = NULL;
    
        char *data = "This is eric's test message from kernel";
    
        printk(KERN_DEBUG "[kernel space] begin kernel_receive
    ");
        skb = skb_get(__skb);
    
        if(skb->len >= sizeof(struct nlmsghdr)){
            nlh = (struct nlmsghdr *)skb->data;
            if((nlh->nlmsg_len >= sizeof(struct nlmsghdr))
                && (__skb->len >= nlh->nlmsg_len)){
                user_process.pid = nlh->nlmsg_pid;
                printk(KERN_DEBUG "[kernel space] data receive from user are:%s
    ", (char *)NLMSG_DATA(nlh));
                printk(KERN_DEBUG "[kernel space] user_pid:%d
    ", user_process.pid);
                send_to_user(data);
            }
        }else{
            printk(KERN_DEBUG "[kernel space] data receive from user are:%s
    ",(char *)NLMSG_DATA(nlmsg_hdr(__skb)));
            send_to_user(data);
        }
    
        kfree_skb(skb);
    }
    
    int __init test_netlink_init(void)
    {
    
        netlinkfd = netlink_kernel_create(&init_net, NETLINK_TEST, 0, kernel_receive, NULL, THIS_MODULE);
        if(!netlinkfd){
            printk(KERN_ERR "can not create a netlink socket
    ");
            return -1;
        }
        return 0;
    }
    
    void __exit test_netlink_exit(void)
    {
        sock_release(netlinkfd->sk_socket);
        printk(KERN_DEBUG "test_netlink_exit!!
    ");
    }
    
    module_init(test_netlink_init);
    module_exit(test_netlink_exit);
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("eric.hu");
    

    用户空间程序代码:user_sent.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <string.h>
    #include <linux/netlink.h>
    
    #define NETLINK_TEST 17
    #define MSG_LEN 100
    
    struct msg_to_kernel
    {
        struct nlmsghdr hdr;
        char data[MSG_LEN];
    };
    struct u_packet_info
    {
        struct nlmsghdr hdr;
        char msg[MSG_LEN];
    };
    
    int main(int argc, char* argv[]) 
    {
        char *data = "This message is from eric's space";
        //初始化
        struct sockaddr_nl local;
        struct sockaddr_nl kpeer;
        int skfd, ret, kpeerlen = sizeof(struct sockaddr_nl);
        struct nlmsghdr *message;
        struct u_packet_info info;
        char *retval;
        message = (struct nlmsghdr *)malloc(1);
    
        skfd = socket(PF_NETLINK, SOCK_RAW, NETLINK_TEST);
        if(skfd < 0){
            printf("can not create a netlink socket
    ");
            return -1;
        }
        memset(&local, 0, sizeof(local));
        local.nl_family = AF_NETLINK;
        local.nl_pid = getpid();
        local.nl_groups = 0;
        if(bind(skfd, (struct sockaddr *)&local, sizeof(local)) != 0){
            printf("bind() error
    ");
            return -1;
        }
        memset(&kpeer, 0, sizeof(kpeer));
        kpeer.nl_family = AF_NETLINK;
        kpeer.nl_pid = 0;
        kpeer.nl_groups = 0;
    
        memset(message, '', sizeof(struct nlmsghdr));
        message->nlmsg_len = NLMSG_SPACE(strlen(data));
        message->nlmsg_flags = 0;
        message->nlmsg_type = 0;
        message->nlmsg_seq = 0;
        message->nlmsg_pid = local.nl_pid;
    
        retval = memcpy(NLMSG_DATA(message), data, strlen(data));
    
        printf("message sendto kernel are:%s, len:%d
    ", (char *)NLMSG_DATA(message), message->nlmsg_len);
        ret = sendto(skfd, message, message->nlmsg_len, 0,(struct sockaddr *)&kpeer, sizeof(kpeer));
        if(!ret){
            perror("send pid:");
            exit(-1);
        }
    
        //接受内核态确认信息
        ret = recvfrom(skfd, &info, sizeof(struct u_packet_info),0, (struct sockaddr*)&kpeer, &kpeerlen);
        if(!ret){
            perror("recv form kerner:");
            exit(-1);
        }
    
        printf("message receive from kernel:%s
    ",(char *)info.msg);
        //内核和用户进行通信
    
        close(skfd);
        return 0;
    }
    

    运行用户程序,输出结果如下:

    [root@FriendlyARM netlink]# ./user_sent
    message sendto kernel are:This message is from eric's space, len:52
    message receive from kernel:This is eric's test message from kernel
    

      

      

      

  • 相关阅读:
    BackgroundWorker原理剖析
    委托异步调用时BeginInvoke的陷阱处理
    线程静态在对象缓存中的妙用
    值得珍藏的.NET源码,不保存就没机会了
    .NET 4.5.1 参考源码索引
    .NET 4.5 参考源码索引
    .NET 4.0 参考源码索引
    WWF3.5SP1 参考源码索引
    WCF3.5 SP1 参考源码索引
    .NET 3.5.1 参考源码索引
  • 原文地址:https://www.cnblogs.com/happygirl-zjj/p/6293759.html
Copyright © 2011-2022 走看看