为了完成内核空间与用户空间通信,Linux提供了基于Socket的NetLink通信机制。
SELinux,Linux系统的防火墙分为内核态的netfilter和用户态的iptables,netfilter与iptables的数据交换就是通过Netlink机制完成。
下面看一个检测usb口的例子:
s32 InitUsbHotPlug(void)
{
s32 nSockFd = 0;
// 套接字地址
struct sockaddr_nl snl;
bzero(&snl, sizeof(struct sockaddr_nl));
// 1.添写套接字地址
snl.nl_family = AF_NETLINK;
snl.nl_pad = 0;
// 设置为处理消息的进程ID。
snl.nl_pid = getpid();
snl.nl_groups = 1;
// 2.创建套接字, 返回套接字文件描述符
// PF_NETLINK - 使用 netlink
// SOCK_DGRAM - 使用不连续不可信赖的数据包连接
// NETLINK_KOBJECT_UEVENT - 内核消息到用户空间,出现在 Linux 2.6.10
nSockFd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (-1 == nSockFd)
{
return -1;
}
// 3.设置套接字接收缓冲区大小
// SOL_SOCKET - 存取 socket 层
// SO_RCVBUF - 设置接收缓冲区大小
// 接收内核发来的消息缓冲区大小
const s32 nRcvBufSize = 1024;
setsockopt(nSockFd, SOL_SOCKET, SO_RCVBUF, &nRcvBufSize, sizeof(nRcvBufSize));
// 4.将套接字加入指定的多播组
s32 nResult = ::bind(nSockFd, (struct sockaddr*)&snl, sizeof(snl));
if (-1 == nResult)
{
close(nSockFd);
return -2;
}
#endif
return nSockFd;
}
上面定义了套接口,以及进行了绑定,下面是接收数据:
void ReceiveUsbMsg(s32 nSockFd)
{
if (nSockFd <= 0)
{
return;
}
// 接收内核发来的消息字符串
s8 achKernelMsg[1024] = { 0 };
// 接收内核消息 (一条消息里有多个字符串,并且字符串之间有截止符'\0'隔开)
s32 recvbytes = recv(nSockFd, achKernelMsg, sizeof(achKernelMsg), 0);
if (recvbytes == 0)
{
return;
}
else if (recvbytes < 0)
{
return;
}
else
{
//进行数据处理
}
}
设置socket的接收缓冲区的大小和获取接收缓冲区的大小
#include <sys/types.h>
#include <sys/socket.h>
Int getsockopt(int sockfd, int level, int optname,
void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen); //设置直接是socklen_t,同int
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
int sock_fd = -1;
//建立socket套接字
sock_fd = socket(AF_INET, SOCK_DGRAM,0);
if( -1 == sock_fd )
{
perror("socket");
exit(1);
}
int recv_get_size = 0;
int len = sizeof(int);
getsockopt( sock_fd, SOL_SOCKET, SO_RCVBUF, &recv_get_size, (socklen_t*)&len);
printf("default recvbuf size: %dk\n", recv_get_size/1024);
const int recv_set_size = 1024;
setsockopt( sock_fd, SOL_SOCKET, SO_RCVBUF, (void*)&recv_set_size, len);
getsockopt( sock_fd, SOL_SOCKET, SO_RCVBUF, &recv_get_size, (socklen_t*)&len);
printf("set get recvbuf size: %dk\n", recv_get_size/1024);
close(sock_fd);
return 0;
}
允许结果如下:
default recvbuf size: 208k
set get recvbuf size: 2k
目前最小缓冲区是2k,设置512字节之后,再获取缓冲区大小还是2k