Netlink套接字是用于用户态和内核态之间的通信。同网络协议中的IPV4、IPV6一样,也是通过socket套接字进行创建的,只是往socket里面传入的参数不一样。通过socket创建好套接字后,IPV4这边的TCP和UDP协议是绑定ip地址+端口号,TCP会根据服务端、客服端的不同进行一些设置,比如服务端的主动变被动listen、等待接收消息accept,客户端请求发送的connect等。UDP不分服务端和客户端,只分发送端和接收端,每个终端之间都会作为发送端和接收端,也会进行一些设置。
Netlink这边也是先通过socket创建一个套接字,重点来了,绑定一个地址,一般是当前进程的pid,也就是getpid(),不同于IPV4绑定ip地址+端口号(根据ip地址的需要自己进行变化),Netlink的初始化基本上就定死了,就是这样,这些参数就是固定的,不需要改变。
9 static int init_hotplug_sock(void)
10 {
11 struct sockaddr_nl snl;
// 定义一个常量整数变量buffersize,表示套接字接收缓冲区的大小为16MB
12 const int buffersize = 16 * 1024 * 1024;
13 int retval;
// 创建一个Netlink套接字,协议族为PF_NETLINK,套接字类型为SOCK_DGRAM,协议为NETLINK_KOBJECT_UEVENT
14
15 int hotplug_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
16 if (hotplug_sock == -1) {
17 printf("error getting socket: %s\n", strerror(errno));
18 return -1;
19 }
// 设置套接字接收缓冲区大小
20
21 setsockopt(hotplug_sock, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));
// 初始化snl结构体
22
23 memset(&snl, 0x00, sizeof(struct sockaddr_nl));
24 snl.nl_family = AF_NETLINK;
25 snl.nl_pid = getpid();
26 snl.nl_groups = 1;
// 绑定套接字到指定的地址
27
28 retval = bind(hotplug_sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl));
29 if (retval < 0) {
30 printf("bind failed: %s\n", strerror(errno));
31 close(hotplug_sock);
32 hotplug_sock = -1;
33 return -1;
34 }
35
36 return hotplug_sock;
37 }
// 创建一个套接字
int hotplug_sock = init_hotplug_sock();
疑问来了,这个套接字是干嘛的?网上很多原理性从内核方面的解释,本菜鸡刚接触linux这一块,看不太懂,本着会用就行的原则,便直观性的感受一下这个套接字到底是个啥
先放结论,当向开发板插上U盘时,hotpulg_sock会自动捕获这些信息:
当U盘从开发板上拔出时,hotpulg_sock会自动捕获这些信息:
通过这些信息,我们可以进行U盘自动挂载的操作,比如,当检测有“add”的时候,mount 挂载XXX,当检测有“remove”的时候,卸载XXX。
记录一下探寻的过程,linux环境编译进行,将生成的可执行文件放在海思开发板上运行,先初始化Netlink套接字,将这个套接字的内容发送给buf,对buf进行打印
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <errno.h>
static int init_hotplug_sock(void)
{
struct sockaddr_nl snl;
const int buffersize = 16 * 1024 * 1024;
int retval;
int hotplug_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (hotplug_sock == -1) {
printf("error getting socket: %s\n", strerror(errno));
return -1;
}
setsockopt(hotplug_sock, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));
memset(&snl, 0x00, sizeof(struct sockaddr_nl));
snl.nl_family = AF_NETLINK;
snl.nl_pid = getpid();
snl.nl_groups = 1;
retval = bind(hotplug_sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl));
if (retval < 0) {
printf("bind failed: %s\n", strerror(errno));
close(hotplug_sock);
hotplug_sock = -1;
return -1;
}
return hotplug_sock;
}
int main()
{
int hotplug_sock = init_hotplug_sock();
if (hotplug_sock == -1) {
return 1;
}
while (true) {
char buf[2048];
int len = recv(hotplug_sock, buf, sizeof(buf), 0);
if (len > 0) {
buf[len] = '\0'; // 确保缓冲区以null结尾
printf("Received message:\n%s\n", buf);
// 在这里可以添加处理逻辑,例如解析设备添加或移除事件
if (strstr(buf, "ACTION=add")) {
printf("Device added:\n");
printf("%s\n", buf);
} else if (strstr(buf, "ACTION=remove")) {
printf("Device removed:\n");
printf("%s\n", buf);
}
} else if (len < 0) {
printf("recv failed: %s\n", strerror(errno));
break;
}
}
close(hotplug_sock);
return 0;
}
使用linux自带的交叉编译工具编译
使用nfs进行文件共享,这地方是将开发板是mnt挂载到了linux的work目录下,在开发板上运行报错:
很纳闷,为啥会报错??第一次意识到了海思快速入门手册里提供的交叉编译工具的作用,使用海思交叉编译工具重新进行编译
重新运行,成功:
往U盘上进行插入和拔出,就会出现最开始的那种现象,把这个套接字的内容打印出来了。
这样的话,开发板上什么也操作不了了,./hotplug_monitor & 这样后台运行会更好一些。