Linux内核 -- Netlink多播组消息处理技术

打印 上一主题 下一主题

主题 1029|帖子 1029|积分 3087

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
Netlink多播组消息处理技术文档

概述

Netlink是一种用户态与内核态之间通信的机制,支持单播和多播模式。多播组答应多个用户态进程接收同一组的广播消息,广泛应用于网络变乱、系统通知等场景。
本文将详细先容如安在内核态发送多播组消息,以及用户态如何接收并处理这些消息。

内核态:发送多播组消息

实现步调


  • 创建Netlink套接字:通过netlink_kernel_create创建一个Netlink套接字。
  • 构建消息:填充nlmsghdr头部和数据部分。
  • 发送消息:利用netlink_broadcast将消息广播到指定多播组。
示例代码

  1. #include <linux/module.h>
  2. #include <linux/netlink.h>
  3. #include <net/sock.h>
  4. #include <linux/skbuff.h>
  5. #define NETLINK_USER 31
  6. #define MULTICAST_GROUP1 (1 << 0)
  7. #define MULTICAST_GROUP2 (1 << 1)
  8. static struct sock *nl_sock = NULL;
  9. // 初始化Netlink套接字
  10. static int __init netlink_init(void) {
  11.     struct netlink_kernel_cfg cfg = {
  12.         .groups = MULTICAST_GROUP1 | MULTICAST_GROUP2, // 支持的多播组
  13.         .input = NULL, // 无需接收消息
  14.     };
  15.     nl_sock = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
  16.     if (!nl_sock) {
  17.         printk(KERN_ERR "Failed to create Netlink socket\n");
  18.         return -ENOMEM;
  19.     }
  20.     printk(KERN_INFO "Netlink socket created\n");
  21.     return 0;
  22. }
  23. // 向多播组发送消息
  24. static void send_multicast_message(const char *message, uint32_t group) {
  25.     struct sk_buff *skb;
  26.     struct nlmsghdr *nlh;
  27.     int msg_size = strlen(message) + 1;
  28.     skb = nlmsg_new(msg_size, GFP_KERNEL);
  29.     if (!skb) {
  30.         printk(KERN_ERR "Failed to allocate sk_buff\n");
  31.         return;
  32.     }
  33.     nlh = nlmsg_put(skb, 0, 0, NLMSG_DONE, msg_size, 0);
  34.     strcpy(nlmsg_data(nlh), message);
  35.     netlink_broadcast(nl_sock, skb, 0, group, GFP_KERNEL);
  36.     printk(KERN_INFO "Message sent to group %u: %s\n", group, message);
  37. }
  38. // 模块加载函数
  39. static int __init netlink_multicast_init(void) {
  40.     int ret = netlink_init();
  41.     if (ret) return ret;
  42.     send_multicast_message("Hello Group 1", MULTICAST_GROUP1);
  43.     send_multicast_message("Hello Group 2", MULTICAST_GROUP2);
  44.     return 0;
  45. }
  46. // 模块卸载函数
  47. static void __exit netlink_multicast_exit(void) {
  48.     if (nl_sock) {
  49.         netlink_kernel_release(nl_sock);
  50.         printk(KERN_INFO "Netlink socket released\n");
  51.     }
  52. }
  53. module_init(netlink_multicast_init);
  54. module_exit(netlink_multicast_exit);
  55. MODULE_LICENSE("GPL");
复制代码

用户态:接收多播组消息

实现步调


  • 创建Netlink套接字:利用socket()创建用户态的Netlink套接字。
  • 订阅多播组:通过setsockopt()将套接字加入一个或多个多播组。
  • 接收消息:利用recvmsg()从套接字中接收消息。
  • 处理消息:解析nlmsghdr头部并处理数据。
示例代码

  1. #include <linux/netlink.h>
  2. #include <sys/socket.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <errno.h>
  7. #include <unistd.h>
  8. #define NETLINK_USER 31
  9. #define MULTICAST_GROUP1 (1 << 0)
  10. #define MULTICAST_GROUP2 (1 << 1)
  11. #define MAX_PAYLOAD 1024
  12. struct nl_msg {
  13.     struct nlmsghdr hdr;
  14.     char data[MAX_PAYLOAD];
  15. };
  16. // 初始化Netlink套接字并订阅多播组
  17. int init_netlink_socket(int *sock_fd, uint32_t groups) {
  18.     struct sockaddr_nl src_addr;
  19.     *sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_USER);
  20.     if (*sock_fd < 0) {
  21.         perror("socket");
  22.         return -1;
  23.     }
  24.     memset(&src_addr, 0, sizeof(src_addr));
  25.     src_addr.nl_family = AF_NETLINK;
  26.     src_addr.nl_pid = getpid(); // 当前进程PID
  27.     src_addr.nl_groups = groups;
  28.     if (bind(*sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr)) < 0) {
  29.         perror("bind");
  30.         close(*sock_fd);
  31.         return -1;
  32.     }
  33.     if (setsockopt(*sock_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &groups, sizeof(groups)) < 0) {
  34.         perror("setsockopt NETLINK_ADD_MEMBERSHIP");
  35.         close(*sock_fd);
  36.         return -1;
  37.     }
  38.     return 0;
  39. }
  40. // 动态加入多播组
  41. int join_multicast_group(int sock_fd, uint32_t group) {
  42.     if (setsockopt(sock_fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)) < 0) {
  43.         perror("setsockopt NETLINK_ADD_MEMBERSHIP");
  44.         return -1;
  45.     }
  46.     printf("Joined multicast group: %u\n", group);
  47.     return 0;
  48. }
  49. // 动态退出多播组
  50. int leave_multicast_group(int sock_fd, uint32_t group) {
  51.     if (setsockopt(sock_fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &group, sizeof(group)) < 0) {
  52.         perror("setsockopt NETLINK_DROP_MEMBERSHIP");
  53.         return -1;
  54.     }
  55.     printf("Left multicast group: %u\n", group);
  56.     return 0;
  57. }
  58. // 接收并处理消息
  59. void receive_messages(int sock_fd) {
  60.     struct nl_msg msg;
  61.     struct sockaddr_nl src_addr;
  62.     struct iovec iov;
  63.     struct msghdr msghdr;
  64.     while (1) {
  65.         memset(&msg, 0, sizeof(msg));
  66.         memset(&src_addr, 0, sizeof(src_addr));
  67.         memset(&msghdr, 0, sizeof(msghdr));
  68.         iov.iov_base = &msg;
  69.         iov.iov_len = sizeof(msg);
  70.         msghdr.msg_name = &src_addr;
  71.         msghdr.msg_namelen = sizeof(src_addr);
  72.         msghdr.msg_iov = &iov;
  73.         msghdr.msg_iovlen = 1;
  74.         int ret = recvmsg(sock_fd, &msghdr, 0);
  75.         if (ret < 0) {
  76.             perror("recvmsg");
  77.             break;
  78.         }
  79.         printf("Received message from group: %u\n", src_addr.nl_groups);
  80.         printf("Message: %s\n", msg.data);
  81.     }
  82. }
  83. int main() {
  84.     int sock_fd;
  85.     uint32_t groups = MULTICAST_GROUP1; // 初始订阅组
  86.     if (init_netlink_socket(&sock_fd, groups) < 0) {
  87.         return -1;
  88.     }
  89.     // 动态加入组2
  90.     join_multicast_group(sock_fd, MULTICAST_GROUP2);
  91.     printf("Listening for multicast messages...\n");
  92.     receive_messages(sock_fd);
  93.     // 动态退出组2
  94.     leave_multicast_group(sock_fd, MULTICAST_GROUP2);
  95.     close(sock_fd);
  96.     return 0;
  97. }
复制代码

总结

通过以上步调,内核态可以发送Netlink多播组消息,用户态可以接收并处理这些消息,同时支持动态加入和退出多播组的功能。本文提供的代码可以用于实际开发中,资助实现高效的内核态与用户态通信。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

慢吞云雾缓吐愁

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表