获得U盘的插入或者拔取得信息的传统方法是在内核级执行hotplug程序。相关參数通过环境变量传递过来,再由hotplug通知其它关注hotplug的应用程序,可是效率比較低.
网上查找知道:
用户空间的程序与设备通信的方法,主要有下面几种方式。
1. 通过ioperm获取操作IOport的权限,然后用inb/inw/ inl/ outb/outw/outl等函数,避开设备驱动程序,直接去操作IOport。(没实用过)
2. 用ioctl函数去操作/dev文件夹下相应的设备,这是设备驱动程序提供的接口。像键盘、鼠标和触摸屏等输入设备一般都是这样做的。
3. 用write/read/mmap去操作/dev文件夹下相应的设备。这也是设备驱动程序提供的接口。像framebuffer等都是这样做的。
上面的方法在大多数情况下,都能够正常工作,可是对于热插拨(hotplug)的设备。比方像U盘,就有点困难了,由于不知道:什么时候设备插上了,什么时候设备拔掉了。
这就是所谓的hotplug问题了。
新的方法是採用NETLINK实现的,这是一种特殊类型的socket。专门用于内核空间与用户空间的异步通信。
先说明几个总要的结构体:
sockaddr_nl结构:
struct sockaddr_nl {
sa_family_t nl_family; //AF_NETLINK
unsigned short nl_pad; // 0
pid_t nl_pid; // 进程pid
u_32 nl_groups; // 多播组掩码
}nl;
int setsockopt(
SOCKET s,
int level,
int optname,
const char* optval,
int optlen
);
s(套接字): 指向一个打开的套接口描写叙述字
level:(级别): 指定选项代码的类型。
SOL_SOCKET: 基本套接口
IPPROTO_IP: IPv4套接口
IPPROTO_IPV6: IPv6套接口
IPPROTO_TCP: TCP套接口
optname(选项名): 选项名称
optval(选项值): 是一个指向变量的指针 类型:整形,套接口结构, 其它结构类型:linger{}, timeval{ }
optlen(选项长度) :optval 的大小
贴出代码:
#include <stdio.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <stdlib.h> #include <linux/netlink.h> #include <dirent.h> #include <sys/statfs.h> int init_socket() { struct sockaddr_nl snl; const int BufferSize= 1024; int retval; memset(&snl,0,sizeof(struct sockaddr_nl)); snl.nl_family = AF_NETLINK; snl.nl_pid = getpid(); snl.nl_groups = 1; int Sock_id = socket(PF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT); if(Sock_id == -1) printf("sock err:%m "),exit(-1); // set reveive buffer setsockopt(Sock_id,SOL_SOCKET,SO_RCVBUFFORCE,&BufferSize,sizeof(BufferSize)); retval = bind(Sock_id,(struct sockaddr*)&snl,sizeof(struct sockaddr_nl)); if(retval==-1) printf("bind err:%m "),close(Sock_id),exit(-1); return Sock_id; } // 该函数主要作用时检測u盘的 总空间,剩余空间,剩余空间百分比 double GetDiskFreeSpacePercent(const char *pDisk,double* freespace,double* totalspace) { struct statfs disk_statfs; double freeSpacePercent =0; if(statfs(pDisk,&disk_statfs) == 0) { *freespace = (disk_statfs.f_bsize * disk_statfs.f_bfree) / (1024*1024*1024.0); *totalspace = (disk_statfs.f_bsize * disk_statfs.f_blocks) / (1024*1024*1024.0); } return freeSpacePercent = (*freespace)/(*totalspace)*100; } #define BUFFER_SIZE 2048 int main() { DIR *dp; double f=0; double t=0; double percent=0; const char* path="/media/cjl/disk"; int sd= init_socket(); while(1) { char buf[BUFFER_SIZE] = {0}; recv(sd,&buf,sizeof(buf),0); //printf("%s ",buf); if(!memcmp(buf,"add@",4) /*&& !memcmp(&buf[strlen(buf) - 4],"/sdb",4)*/) { printf("Found U Disk "); break; } } printf("是否打开u盘Y/N "); char c; scanf("%c",&c); if(c=='Y' || c=='y') { if((dp = opendir(path)) ==NULL) { printf("打开失败! "); } else { system("ls -l /media/cjl/disk"); } } else if(c=='N' || c=='n') percent = GetDiskFreeSpacePercent(path,&f,&t); printf("u盘剩余空间: %.2f ",f); printf("u盘总空间: %.2f ",t); printf("u盘剩余空间百分比: %0.2f%% ",percent); return 0; }