AF_NETLINK和PF_NETLINK的区别
时间: 2024-06-20 11:00:46 浏览: 408
AF_NETLINK是Linux内核中的一种网络协议族(Address Family),用于在用户空间和内核空间之间传递网路链接(NETLINK)消息。它主要用于进程间通信,特别是在内核模块与用户空间程序之间的通信,比如系统监控工具、网络设备驱动程序等。
PF_NETLINK则是AF_NETLINK中的协议类型(Protocol Type)。每个网络协议族可以有多个协议类型,它们代表了不同的功能或用途。PF_NETLINK通常指的是标准的NETLINK协议类型,它支持基本的网络链接消息,如套接字操作、路由更改等。用户空间应用程序使用PF_NETLINK来连接到内核,发送和接收NETLINK消息。
简单来说,AF_NETLINK是网络协议族的总称,而PF_NETLINK是该协议族内的具体协议实现。区别如下:
1. **AF_NETLINK**:是一个抽象层,定义了如何在用户空间和内核之间传递网络消息。
2. **PF_NETLINK**:是AF_NETLINK的一个实例,表示用于普通网络链接操作的协议类型。
相关问题
在Linux C开发场景中,基于 AF_NETLINK 实现客户端和服务器的socket通信,要求生成的代码可以正常运行
在Linux C开发中,AF_NETLINK是一种特殊的网络套接字类型,主要用于进程间通信(IPC),特别是用于内核到用户空间的通信。要基于`AF_NETLINK`实现客户端和服务端的socket通信,你需要了解以下几个关键点:
1. **包括必要的头文件**:
- 包含`linux/netlink.h`和`linux/uapi/linux/netlink.h`,它们定义了netlink消息的结构和函数原型。
```c
#include <linux/netlink.h>
#include <uapi/linux/netlink.h>
```
2. **创建套接字**:
- 客户端通常需要调用`socket(PF_NETLINK, SOCK_RAW, NETLINK_USER)`创建一个NETLINK类型的套接字,并选择NETLINK_USER标志来标识这是一个用户空间应用。
- 服务端则可能使用`socket(AF_NETLINK, SOCK_SEQPACKET | SOCK_CLOEXEC, NLPROTO)`创建一个序列化套接字。
3. **设置接收/发送数据结构**:
- 创建`struct sockaddr_nl`地址结构,其中包含了netlink ID、家族(PF_NETLINK)、组ID等信息。
- 使用`msg_iov()`结构体来传递netlink消息的数据部分,以及`msg_iovec_count`。
4. **发送消息**(服务端):
- 调用`sendmsg()`函数,传递创建好的`struct msghdr`结构和`struct sockaddr_nl`。
5. **接收消息**(客户端):
- 使用`recvmsg()`函数读取消息,同样通过`msghdr`和`sockaddr_nl`。
6. **处理netlink消息**:
- 解析收到的消息,可能涉及解析包含在`nlmsg_data()`内的自定义数据。
7. **错误处理**:
- 对于可能出现的错误,如连接失败、接收超时等,记得捕获并处理异常。
示例代码片段(简化版):
```c
// 客户端示例
#include <stdio.h>
#include <linux/netlink.h>
int main() {
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_USER);
struct sockaddr_nl sa;
// ...填充sa...
char buf[NETLINK_MSG_SIZE];
// ...构建并发送数据...
close(sock);
return 0;
}
// 服务端示例
#include <stdio.h>
#include <linux/netlink.h>
int main() {
int sock = socket(AF_NETLINK, SOCK_SEQPACKET | SOCK_CLOEXEC, NLPROTO);
// ...监听和接受请求...
close(sock);
return 0;
}
```
linux如何创建PF_NETLINK协议通信,写出服务端和客户端
PF_NETLINK是Linux内核提供的一种用于内核与用户空间进程之间通信的协议。下面是一个简单的PF_NETLINK服务端和客户端的示例代码:
服务端代码:
```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#define NETLINK_TEST 25
#define MSG_LEN 100
int main(int argc, char *argv[]) {
int skfd;
struct sockaddr_nl saddr, daddr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
struct msghdr msg;
char msg_buf[MSG_LEN];
// 创建socket
skfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
if (skfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
// 绑定源地址
memset(&saddr, 0, sizeof(saddr));
saddr.nl_family = AF_NETLINK;
saddr.nl_pid = getpid();
saddr.nl_groups = 0;
if (bind(skfd, (struct sockaddr *)&saddr, sizeof(saddr)) != 0) {
perror("bind");
close(skfd);
exit(EXIT_FAILURE);
}
// 初始化目标地址
memset(&daddr, 0, sizeof(daddr));
daddr.nl_family = AF_NETLINK;
daddr.nl_pid = 0; // 目标地址为内核
daddr.nl_groups = 0;
// 构造netlink消息
nlh = (struct nlmsghdr *)msg_buf;
nlh->nlmsg_len = NLMSG_LENGTH(strlen("Hello from kernel!"));
nlh->nlmsg_pid = getpid();
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh), "Hello from kernel!");
// 设置iov
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
// 设置msghdr
memset(&msg, 0, sizeof(msg));
msg.msg_name = (void *)&daddr;
msg.msg_namelen = sizeof(daddr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
// 发送消息
if (sendmsg(skfd, &msg, 0) == -1) {
perror("sendmsg");
close(skfd);
exit(EXIT_FAILURE);
}
printf("Kernel message sent.\n");
close(skfd);
return 0;
}
```
客户端代码:
```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#define NETLINK_TEST 25
#define MSG_LEN 100
int main(int argc, char *argv[]) {
int skfd;
struct sockaddr_nl saddr, daddr;
struct nlmsghdr *nlh = NULL;
struct iovec iov;
struct msghdr msg;
char msg_buf[MSG_LEN];
// 创建socket
skfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_TEST);
if (skfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
// 初始化源地址
memset(&saddr, 0, sizeof(saddr));
saddr.nl_family = AF_NETLINK;
saddr.nl_pid = getpid();
saddr.nl_groups = 0;
// 绑定源地址
if (bind(skfd, (struct sockaddr *)&saddr, sizeof(saddr)) != 0) {
perror("bind");
close(skfd);
exit(EXIT_FAILURE);
}
// 初始化目标地址
memset(&daddr, 0, sizeof(daddr));
daddr.nl_family = AF_NETLINK;
daddr.nl_pid = 0; // 目标地址为内核
daddr.nl_groups = 0;
// 构造netlink消息
nlh = (struct nlmsghdr *)msg_buf;
nlh->nlmsg_len = NLMSG_SPACE(MSG_LEN);
nlh->nlmsg_pid = getpid();
nlh->nlmsg_flags = 0;
strcpy(NLMSG_DATA(nlh), "Hello from user space!");
// 设置iov
iov.iov_base = (void *)nlh;
iov.iov_len = nlh->nlmsg_len;
// 设置msghdr
memset(&msg, 0, sizeof(msg));
msg.msg_name = (void *)&daddr;
msg.msg_namelen = sizeof(daddr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
// 发送消息
if (sendmsg(skfd, &msg, 0) == -1) {
perror("sendmsg");
close(skfd);
exit(EXIT_FAILURE);
}
printf("User message sent.\n");
// 接收消息
memset(&msg, 0, sizeof(msg));
msg.msg_name = (void *)&saddr;
msg.msg_namelen = sizeof(saddr);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
if (recvmsg(skfd, &msg, 0) == -1) {
perror("recvmsg");
close(skfd);
exit(EXIT_FAILURE);
}
printf("Received message from kernel: %s\n", (char *)NLMSG_DATA(nlh));
close(skfd);
return 0;
}
```
运行上述服务端和客户端代码即可进行PF_NETLINK通信。注意需要以root权限运行程序。
阅读全文