Netlink实现Linux内核与用户空间通信
作者:网络转载 发布时间:[ 2014/1/17 9:32:07 ] 推荐标签:Linux 内核 通信
函数 bind() 用于把一个打开的 netlink socket 与 netlink 源 socket 地址绑定在一起。netlink socket 的地址结构如下:
view plaincopy to clipboardprint?
struct sockaddr_nl {
sa_family_t nl_family;
unsigned short nl_pad;
__u32 nl_pid;
__u32 nl_groups;
};
字段 nl_family 必须设置为 AF_NETLINK 或着 PF_NETLINK,字段 nl_pad 当前没有使用,因此要总是设置为 0,字段 nl_pid 为接收或发送消息的进程的 ID,如果希望内核处理消息或多播消息,把该字段设置为 0,否则设置为处理消息的进程 ID。字段 nl_groups 用于指定多播组,bind 函数用于把调用进程加入到该字段指定的多播组,如果设置为 0,表示调用者不加入任何多播组。
view plaincopy to clipboardprint?
struct timeval timeout;
memset(&client, 0, sizeof(client));
client.nl_family = AF_NETLINK;
client.nl_pid = getpid();
client.nl_groups = 1; /* receive broadcast message*/
传递给 bind 函数的地址的 nl_pid 字段应当设置为本进程的进程 ID,这相当于 netlink socket 的本地地址。但是,对于一个进程的多个线程使用 netlink socket 的情况,字段 nl_pid 则可以设置为其它的值,因此字段 nl_pid 实际上未必是进程 ID,它只是用于区分不同的接收者或发送者的一个标识,用户可以根据自己需要设置该字段。函数 bind 的调用方式如下:
view plaincopy to clipboardprint?
bind(ntSocket, (struct sockaddr*)&client, sizeof(client))
ntSocket为前面的 socket 调用返回的文件描述符,参数 client 为 struct sockaddr_nl 类型的地址。为了接收来自ntSocket的内核通知数据,显然要监听ntSocket的可读性,当select监听到ntSocket的可读事件时,调用recv函数接收内核传递过来的通知数据即可。整个过程完整的C语言实现过程如下:
view plaincopy to clipboardprint?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#define UEVENT_BUFFER_SIZE 2048
int main(void)
{
struct sockaddr_nl client;
struct timeval tv;
int ntSocket, rcvlen, ret;
fd_set fds;
int buffersize = 1024;
ntSocket = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
memset(&client, 0, sizeof(client));
client.nl_family = AF_NETLINK;
client.nl_pid = getpid();
client.nl_groups = 1; /* receive broadcast message*/
setsockopt(ntSocket, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
bind(ntSocket, (struct sockaddr*)&client, sizeof(client));
while (1) {
char buf[UEVENT_BUFFER_SIZE] = { 0 };
FD_ZERO(&fds);
FD_SET(ntSocket, &fds);
tv.tv_sec = 0;
tv.tv_usec = 100 * 1000;
ret = select(ntSocket + 1, &fds, NULL, NULL, &tv);
if(!(ret > 0 && FD_ISSET(ntSocket, &fds)))
continue;
/* receive data */
rcvlen = recv(ntSocket, &buf, sizeof(buf), 0);
if (rcvlen > 0) {
printf("%s
", buf);
// You can do something here to make the program more perfect!!!
}
}
close(ntSocket);
return 0;
}

sales@spasvo.com