香港高速VIP云机房火爆上线啦!无需备案,开通即用!配套《巅云自助建站系统3.0》将带给您飞一般的可视化拖拽建站体验,欢迎免费体验。

linux下用户程序同内核通信详解(netlink机制)

一佰互联网站制作(www.yinxi.net) 发布日期 2019-04-23 09:20:56 浏览数: 10

简介

linux下用户程序同内核通信的方式一般有ioctl, proc文件系统,剩下一个就是Netlink套接字了。 这里先介绍下netlink。

Netlink 是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的 socket API 就可以使用 netlink 提供的强大功能,内核态需要使用专门的内核 API 来使用 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机制实现用户程序和内核的通信。 具体就是用户程序执行./netlink -S [我是参数] 或./netlink -G 时,内核会返回"S know you!" 和“I know you!” 这两种字符串, 然后输出。 内核和用户程序均加有打印。

内核模块

1. Makefile依赖的编译规则 ruler.dir

PWD := $(shell pwd)  all: modules romfs  modules:  $(MAKE) -C $(KDIR) M=$(PWD) modules  @echo $(OBJ)  modules_install:  $(MAKE) -C $(KDIR) M=$(PWD) modules_install  romfs:  cp -rf *.ko $(MODULES_BUILD_DIR)  clean:  rm *.o *.ko *.mod.* Module.* modules.*  rm -rf $(MODULES_BUILD_DIR)  obj-m := $(MOD_NAME).o 

2.Makefile

KERNEL_MODULES := netlink  export MODULES_ROOT_DIR := $(shell pwd) export MODULES_BUILD_DIR := $(MODULES_ROOT_DIR)/build export KDIR := /lib/modules/$(shell uname -r)/build #这行是为了取出系统下内核的目录(ubuntu)  all: init modules romfs  init:  mkdir -p $(MODULES_BUILD_DIR)  modules:$(patsubst %, _dir_%, $(KERNEL_MODULES))  $(patsubst %, _dir_%, $(KERNEL_MODULES)):  @echo  @echo Building $(patsubst _dir_%, %, $@)  $(MAKE) -C $(patsubst _dir_%, %, $@) all   romfs: $(patsubst %, _romfs_%, $(KERNEL_MODULES)) $(patsubst %, _romfs_%, $(KERNEL_MODULES)):  $(MAKE) -C $(patsubst _romfs_%, %, $@) romfs   clean: $(patsubst %, _clean_%, $(KERNEL_MODULES))  $(RM) $(BUILD_DIR) $(patsubst %, _clean_%, $(KERNEL_MODULES)):  @echo  @echo Cleaning $(patsubst _dir_%, %, $@)  $(MAKE) -C $(patsubst _clean_%, %, $@) clean  .PHONY: 

3. ./netlink/netlink.c

/*  * netlink.c  *  * Created on: 2014 *  Author: cr  */  #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/skbuff.h> #include <linux/ip.h> #include <linux/types.h> #include <linux/sched.h> #include <linux/netlink.h> #include <net/sock.h> #include "usrlink.h"  MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("MDAXIA");  struct sock *netlink_fd;   static void netlink_to_user(int dest, void *buf, int len) {  struct nlmsghdr *nl;  struct sk_buff *skb;  int size;   size = NLMSG_SPACE(len);  skb = alloc_skb(size, GFP_ATOMIC);  if(!skb || !buf)  {   printk(KERN_ALERT "netlink_to_user skb of buf null!");   return;  }  nl = nlmsg_put(skb, 0, 0, 0, NLMSG_SPACE(len) - sizeof(struct nlmsghdr), 0);  NETLINK_CB(skb).pid = 0;  NETLINK_CB(skb).dst_group = 0;   memcpy(NLMSG_DATA(nl), buf, len);  nl->nlmsg_len = (len > 2) ? (len - 2):len;   netlink_unicast(netlink_fd, skb, dest, MSG_DONTWAIT);  printk(KERN_ALERT "K send packet success"); }  static int process_hello_get(int dest, void *buf, int len) {  printk(KERN_ALERT "In process_hello get!");  memcpy(buf, "I known you !", 13);  netlink_to_user(dest, buf, 13);  return NET_OK; }  static int process_hello_set(int dest, void *buf, int len) {  printk(KERN_ALERT "In process_hello set! %s", (char *)buf);  memcpy(buf, "S known you !", 13);  netlink_to_user(dest, buf, 13);  return NET_OK; }   static void netlink_process_packet(struct nlmsghdr *nl) {  int ret;   switch(nl->nlmsg_type)  {  case HELLO_GET:   ret = process_hello_get(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len);   break;  case HELLO_SET:   ret = process_hello_set(nl->nlmsg_pid, NLMSG_DATA(nl), nl->nlmsg_len);   break;  default:break;  } }  static void netlink_recv_packet(struct sk_buff *__skb) {  struct sk_buff *skb;  struct nlmsghdr *nlhdr;   skb = skb_get(__skb);  if(skb->len >= sizeof(struct nlmsghdr))  {   nlhdr = (struct nlmsghdr *)skb->data;   if(nlhdr->nlmsg_len >= sizeof(struct nlmsghdr) &&     __skb->len >= nlhdr->nlmsg_len)   {    netlink_process_packet(nlhdr);   }  }  else   printk(KERN_ALERT "Kernel receive msg length error!"); }  static int __init netlink_init(void) {  netlink_fd = netlink_kernel_create(&init_net, USER_NETLINK_CMD, 0, netlink_recv_packet, NULL, THIS_MODULE);  if(NULL == netlink_fd)  {   printk(KERN_ALERT "Init netlink!");   return -1;  }  printk(KERN_ALERT "Init netlink success!");  return 0; }  static void __exit netlink_exit(void) {  netlink_kernel_release(netlink_fd);  printk(KERN_ALERT "Exit netlink!"); }  module_init(netlink_init); module_exit(netlink_exit); 

4. ./netlink/usrlink.h

/*  * usrlink.h  *  * Created on: 2014骞?鏈?7鏃? *  Author: cr  */ #ifndef USRLINK_H_ #define USRLINK_H_  #define USER_NETLINK_CMD 25 #define MAXMSGLEN   1024  typedef enum error_e {  NET_ERROR,  NET_OK,  NET_PARAM,  NET_MEM,  NET_SOCK, } netlink_err;  typedef enum module_e {  HELLO_CMD = 1, } netlink_module;  typedef enum type_e {  HELLO_SET,  HELLO_GET, } netlink_type;  #endif /* USRLINK_H_ */ 

5. ./netlink/Makefile

MOD_NAME := netlink  $(MOD_NAME)-objs : netlink.o  -include $(MODULES_ROOT_DIR)/rules.dir  .PHONY: 

6. 编译方式

其中Makefile、rulers.dir 在Knetlink/下, netlink.c 、netlink.h 、Makefile在Knetlink/netlink/目录下。 编译时在Knetlink目录下执行Make即可

用户程序

用户程序的Makefile 这里就不放出了。 我是直接在eclipse下建的工程 自动编译的、...

1. netlink.c

/*  * usrlink.c  *  * Created on: 2014骞?鏈?7鏃? *  Author: cr  */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "usrlink.h"  int netlink_sock_init(netlink_sock *netlink_s, int module, int protocol) {  netlink_s->sock = socket(PF_NETLINK, SOCK_RAW, protocol);  if(netlink_s->sock < 0)   return NET_SOCK;  memset(&netlink_s->src, 0 ,sizeof(netlink_s->src));  netlink_s->src.nl_family = AF_NETLINK;  netlink_s->src.nl_pid = module;  netlink_s->src.nl_groups = 0;   if(bind(netlink_s->sock, (struct sockaddr *)&netlink_s->src, sizeof(netlink_s->src)) < 0)   return NET_SOCK;   netlink_s->dest.nl_family = AF_NETLINK;  netlink_s->dest.nl_pid = 0;  netlink_s->dest.nl_groups = 0;   return NET_OK; }  int netlink_send(netlink_sock *netlink_s, int type, char *sbuf, int slen, char *rbuf, int *rlen) {  struct msghdr msg;  struct nlmsghdr *nlhdr = NULL;  struct iovec iov;  int ret;   nlhdr = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAXMSGLEN));  if(NULL == nlhdr)   return NET_MEM;   memcpy(NLMSG_DATA(nlhdr), sbuf, slen);  nlhdr->nlmsg_len = NLMSG_SPACE(slen);  nlhdr->nlmsg_pid = netlink_s->src.nl_pid;  nlhdr->nlmsg_type = type;  nlhdr->nlmsg_flags = 0;   iov.iov_base = (void *)nlhdr;  iov.iov_len = nlhdr->nlmsg_len;   msg.msg_name = (void *)&(netlink_s->dest);  msg.msg_namelen = sizeof(netlink_s->dest);  msg.msg_iov = &iov;  msg.msg_iovlen = 1;   ret = sendmsg(netlink_s->sock, &msg, 0);  if(ret < 0)  {   printf("Send fail");   goto error;  }  ret = recvmsg(netlink_s->sock, &msg, 0);  if(ret < 0)  {   printf("Read fail");   goto error;  }  memcpy(rbuf, NLMSG_DATA(nlhdr), nlhdr->nlmsg_len);  *rlen = nlhdr->nlmsg_len;  return NET_OK;  error:  free(nlhdr);  return NET_SOCK; }  int netlink_sock_deinit(netlink_sock *netlink_s) {  close(netlink_s->sock);  memset(netlink_s, 0, sizeof(netlink_sock));  return NET_OK; } 

2. netlink.h

/*  * usrlink.h  *  * Created on: 2014 *  Author: cr  */ #include <sys/types.h> #include <sys/socket.h> #include <asm/types.h> #include <linux/socket.h> #include <linux/netlink.h> #ifndef USRLINK_H_ #define USRLINK_H_  #define USER_NETLINK_CMD 25 #define MAXMSGLEN   1024  typedef enum error_e {  NET_ERROR,  NET_OK,  NET_PARAM,  NET_MEM,  NET_SOCK, } netlink_err;  typedef enum module_e {  HELLO_CMD = 1, } netlink_module;  typedef enum type_e {  HELLO_SET,  HELLO_GET, } netlink_type;  typedef struct usr_sock_h {  int sock;  struct sockaddr_nl dest;  struct sockaddr_nl src; } netlink_sock;  int netlink_sock_init(netlink_sock *netlink_s, int module, int protocol); int netlink_sock_deinit(netlink_sock *netlink_s); int netlink_send(netlink_sock *netlink_s, int type, char *sbuf, int slen, char *rbuf, int *rlen);  #endif /* USRLINK_H_ */ 

3. main.c

/*  * main.c  *  * Created on: 2014骞?鏈?7鏃? *  Author: cr  */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "usrlink.h"  int parse_ret(int ret) {  switch(ret)  {  case NET_OK:   return ret;  case NET_ERROR:   printf("error");   goto exit_p;  case NET_MEM:   printf("Memory error");   goto exit_p;  case NET_PARAM:   printf("Param error");   goto exit_p;  case NET_SOCK:   printf("Socket error");   goto exit_p;  default:break;  } exit_p:  return NET_ERROR; }  void usage(void) {  printf("Usage: Netlink -G <param>	-S <param>"); }  int main(int argc, char **argv) {  netlink_sock h_sock;  char rbuf[1024];  char sbuf[1024];  int ret, type, slen = 0, rlen = 0;   ret = netlink_sock_init(&h_sock, HELLO_CMD, USER_NETLINK_CMD);  if(NET_OK != parse_ret(ret))   goto exit_p;   bzero(&rbuf, sizeof(rbuf));  bzero(&sbuf, sizeof(sbuf));  if(argc < 3)  {   usage();   goto exit_p;  }  if(!strncmp("-G", argv[1], 2))   type = HELLO_GET;  else if(!strncmp("-S", argv[1], 2))   type = HELLO_SET;   strcpy(sbuf, argv[2]);  slen = strlen(sbuf);  ret = netlink_send(&h_sock, type, sbuf, slen, rbuf, &rlen);  if(NET_OK != parse_ret(ret))   goto exit_p;   if(rlen > 0)  {   rbuf[rlen] = "";   printf("K rep [len = %d]:%s", rlen, rbuf);  }  printf("K[len = %d]: %s", rlen, rbuf);  exit_p:  netlink_sock_deinit(&h_sock);  return 0; } 

总结

以上就是本文关于linux下用户程序同内核通信详解(netlink机制)的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

一佰互联是全国知名建站品牌服务商,我们有九年网站建设、网站制作、网页设计、php开发和域名注册及虚拟主机服务经验,提供的自助建站服务更是全国有名。近年来还整合团队优势自主开发了可视化多用户”巅云建站系统“3.0平台版,拖拽排版网站制作设计,轻松实现pc站、手机微网站、小程序、APP一体化全网营销网站建设 ,已成功的为全国上百家网络公司提供自助建站平台搭建服务。

相关新闻more

27
03月
少儿培训机构运营实战案例(延伸产品篇)

简介:案例一:童星经纪功能:塑造教学标杆、品牌明星效应、经营内容补充实例:学生小琪(小名)是我机构地方分店的舞蹈及声乐课学员,在机构学习两年... >>详情

28
04月
php中最简单的字符串匹配算法

本文实例讲述了php中最简单的字符串匹配算法。分享给大家供大家参考。具体实现方法如下:复制代码 代码如下:<?php /* 最... >>详情

26
04月
PHP获取表单数据与HTML嵌入PHP脚本的

php接受通过HTML表单提交的信息时,会将提交的数据保存在全局数组中,我们可以调用系统特定的自动全局变量数组来获取这些值。常用的自动全局变... >>详情

14
05月
seo排名教程_巅云建站

ta charset="UTF-8"> seo排名教程_巅云建站 a:hover, a:focus,.post-like.acti... >>详情

营业执照. cdn加速服务 备案系统认证 网络安全协会 我们的支付方式AAA认证
上海 北京 深圳 广州 天津 杭州 南京 武汉 成都 沈阳 大连 长沙 济南 青岛 苏州 福州 无锡 哈尔滨 宁波 重庆 大庆 厦门 西安 长春 珠海 郑州 海口 昆明 太原 石家庄 温州 合肥 乌鲁木齐 南宁 南通 合肥 兰州 呼和浩特 贵阳 烟台 秦皇岛 包头 唐山 银川 汕头 连云港 威海 西宁 湛江 北海 万州 涪陵 长寿 黔江 永川 丰都 忠县 江津 南川 开县 云阳 万盛 梁平 垫江 巫山 城口 建站宝盒 免费建站 门户网站建设 微信网站 手机网站 门户网站制作

7x24小时服务电话:18581389571 传真:023-85725751 免费建站交流群:236412099 139947842(自助建站交流) E-Mail:post@yinxi.net 网站投诉:
重庆楚捷科技有限公司 一佰互联©版权所有 自助建站(www.yinxi.net,Inc.) 2001-2020 All Rights Reserved 本站程序受法律保护,网站法律顾问:ITLAW-庄毅雄律师
中华人民共和国信息产业部网站备案号:渝ICP备12000592号