在healthd中,有一个很好的例子,特地截取下来作为参考:
首先是
static int uevent_fd;
static int eventct;
static int epollfd;
int uevent_open_socket(int buf_sz, bool passcred)
{
struct sockaddr_nl addr;
int on = passcred;
int s;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = 0xffffffff;
s = socket(PF_NETLINK#协议族, SOCK_DGRAM | SOCK_CLOEXEC#指定的socket类型-无保障的面向消息的socket, NETLINK_KOBJECT_UEVENT#特殊的uevent类型的socket);
if(s < 0)
return -1;
setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &buf_sz, sizeof(buf_sz));
setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
#
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
sockfd:标识一个套接口的描述字。
level:选项定义的层次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6。
optname:需设置的选项。
optval:
指针,指向存放选项待设置的新值的
缓冲区。
optlen:optval缓冲区长度
#
if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
#
参数sockfd
指定地址与哪个套接字绑定,这是一个由之前的socket函数调用返回的套接字。调用bind的函数之后,该套接字与一个相应的地址关联,发送到这个地址的数据可以通过这个套接字来读取与使用。
参数addr
指定地址。这是一个地址结构,并且是一个已经经过填写的有效的地址结构。调用bind之后这个地址与参数sockfd指定的套接字关联,从而实现上面所说的效果。
参数addrlen
正如大多数socket接口一样,内核不关心地址结构,当它复制或传递地址给驱动的时候,它依据这个值来确定需要复制多少数据。这已经成为socket接口中最常见的参数之一了。
#
close(s);
return -1;
}
return s;
}
static void uevent_init(void) {
uevent_fd = uevent_open_socket(64*1024, true);
if (uevent_fd < 0) {
KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
return;
}
fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
#fcntl()针对(文件)描述符提供控制.参数fd 是被参数cmd操作(如下面的描述)的描述符
if (healthd_register_event(uevent_fd, uevent_event)) //收到event之后的处理函数
KLOG_ERROR(LOG_TAG,
"register for uevent events failed\n");
// close(uevent_fd);
}
int healthd_register_event(int fd, void (*handler)(uint32_t)) {
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLWAKEUP;
ev.data.ptr = (void *)handler;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
#该函数用于控制某个epoll文件描述符上的事件,可以注册事件,修改事件,删除事件
KLOG_ERROR(LOG_TAG,
"epoll_ctl failed; errno=%d\n", errno);
return -1;
}
eventct++;
return 0;
}
static void healthd_mainloop(void) {
while (1) {
struct epoll_event events[eventct];
int nevents;
int timeout = awake_poll_interval;
nevents = epoll_wait(epollfd, events, eventct, timeout);
}
这样就把uevent和socket以及处理的handler联系到了一起