netlink 实现非阻塞数据的完整示例
时间: 2023-09-20 18:03:38 浏览: 69
以下是一个使用 netlink 实现非阻塞数据传输的示例程序。该程序使用 netlink 套接字与内核通信,并使用 poll 函数实现非阻塞模式。
首先,我们需要包含必要的头文件:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <poll.h>
```
接下来,我们定义一些常量和变量:
```c
#define MAX_PAYLOAD 1024 /* 最大消息长度 */
#define NETLINK_USER 31 /* 自定义 netlink 协议 */
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd, ret;
char *msg = "Hello from userspace!";
```
接着,我们创建一个 netlink 套接字:
```c
/* 创建 netlink 套接字 */
sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_USER);
if (sock_fd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
```
然后,我们初始化源地址和目标地址:
```c
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid(); /* PID */
src_addr.nl_groups = 0; /* 不加入多播组 */
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; /* 内核进程 */
dest_addr.nl_groups = 0;
```
接下来,我们将 netlink 套接字绑定到源地址:
```c
/* 绑定 netlink 套接字到源地址 */
ret = bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
if (ret < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
```
然后,我们构造 netlink 消息:
```c
/* 构造 netlink 消息 */
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = getpid(); /* PID */
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh), msg);
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
/* 发送 netlink 消息 */
sendmsg(sock_fd, &iov, 1, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
```
接下来,我们使用 poll 函数实现非阻塞模式:
```c
/* 设置 poll 监听套接字 */
struct pollfd fds;
fds.fd = sock_fd;
fds.events = POLLIN;
/* 轮询监听 netlink 套接字 */
while (1) {
ret = poll(&fds, 1, 5000); /* 5 秒超时 */
if (ret < 0) {
perror("poll");
exit(EXIT_FAILURE);
} else if (ret == 0) {
printf("timeout\n");
} else if (fds.revents & POLLIN) {
/* 接收 netlink 消息 */
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov.iov_base = (void *)nlh;
iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
ret = recvmsg(sock_fd, &msg, 0);
if (ret < 0) {
perror("recvmsg");
exit(EXIT_FAILURE);
}
printf("Received message: %s\n", NLMSG_DATA(nlh));
break;
}
}
```
最后,我们关闭 netlink 套接字并释放资源:
```c
/* 关闭 netlink 套接字并释放资源 */
close(sock_fd);
free(nlh);
```
完整的程序代码如下:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <poll.h>
#define MAX_PAYLOAD 1024 /* 最大消息长度 */
#define NETLINK_USER 31 /* 自定义 netlink 协议 */
int main()
{
struct sockaddr_nl src_addr, dest_addr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
int sock_fd, ret;
char *msg = "Hello from userspace!";
/* 创建 netlink 套接字 */
sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_USER);
if (sock_fd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
/* 初始化源地址和目标地址 */
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid(); /* PID */
src_addr.nl_groups = 0; /* 不加入多播组 */
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0; /* 内核进程 */
dest_addr.nl_groups = 0;
/* 绑定 netlink 套接字到源地址 */
ret = bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr));
if (ret < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
/* 构造 netlink 消息 */
nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD));
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
nlh->nlmsg_pid = getpid(); /* PID */
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh), msg);
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
/* 发送 netlink 消息 */
sendmsg(sock_fd, &iov, 1, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
/* 设置 poll 监听套接字 */
struct pollfd fds;
fds.fd = sock_fd;
fds.events = POLLIN;
/* 轮询监听 netlink 套接字 */
while (1) {
ret = poll(&fds, 1, 5000); /* 5 秒超时 */
if (ret < 0) {
perror("poll");
exit(EXIT_FAILURE);
} else if (ret == 0) {
printf("timeout\n");
} else if (fds.revents & POLLIN) {
/* 接收 netlink 消息 */
memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD));
iov.iov_base = (void *)nlh;
iov.iov_len = NLMSG_SPACE(MAX_PAYLOAD);
ret = recvmsg(sock_fd, &msg, 0);
if (ret < 0) {
perror("recvmsg");
exit(EXIT_FAILURE);
}
printf("Received message: %s\n", NLMSG_DATA(nlh));
break;
}
}
/* 关闭 netlink 套接字并释放资源 */
close(sock_fd);
free(nlh);
return 0;
}
```