Detecting the connection and disconnection of the network cable under Linux

        The NETLINK_SOCKET provided by the Linux kernel can be used to detect the link down and link up events of the network cable connection in a non-query mode.

        NETLINK_SOCKET is a mechanism provided by the Linux kernel for inter-process communication, which allows two-way communication between user processes and kernel processes. You can subscribe and receive kernel events through NETLINK_SOCKET, such as changes in the status of network cable connections.

        In a C program, you can use NETLINK_SOCKET to subscribe to kernel events and be notified when the event occurs. The specific implementation steps are as follows:

  1. Create a NETLINK_SOCKET socket;
  2. Bind to the NETLINK_KOBJECT_UEVENT message type;
  3. Subscribe to events "add" and "remove";
  4. Receive kernel events cyclically;
  5. In the event processing function, determine the event type and perform corresponding operations.

        Here is a simple sample code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <unistd.h>

#define NETLINK_KOBJECT_UEVENT 15
#define UEVENT_BUFFER_SIZE 2048

void handle_uevent(int sock) {
    char buffer[UEVENT_BUFFER_SIZE];
    ssize_t len;

    while ((len = recv(sock, buffer, sizeof(buffer), 0)) > 0) {
        int i;
        for (i = 0; i < len; i++) {
            if (buffer[i] == '\0') {
                printf("%s\n", &buffer[i] + 1);  // 事件信息在'\0'后面
            }
        }
    }
}

int main(int argc, char *argv[]) {
    struct sockaddr_nl addr;
    int sock;

    sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
    if (sock == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    memset(&addr, 0, sizeof(addr));
    addr.nl_family = AF_NETLINK;
    addr.nl_groups = 1 << (NETLINK_KOBJECT_UEVENT - 1);

    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
        perror("bind");
        close(sock);
        exit(EXIT_FAILURE);
    }

    while (1) {
        handle_uevent(sock);
    }

    close(sock);

    return 0;
}

        In the above code, first create a NETLINK_SOCKET socket and bind it to the NETLINK_KOBJECT_UEVENT message type, then subscribe to the events "add" and "remove", and finally receive kernel events in a loop and judge the event type in the event processing function and perform corresponding operations.

When the connection state of the network cable changes, the kernel will generate a UEVENT event and send the event information to the NETLINK_KOBJECT_UEVENT socket. The C program subscribes to and receives this event through NETLINK_SOCKET, and can obtain event information in the event processing function and determine the change type of the network cable connection status.

#include <sys/types.h>
#include <sys/socket.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <string.h>

#define BUFLEN 20480

int main(int argc, char *argv[])
{
	int fd, retval;
	char buf[BUFLEN] = { 0 };
	int len = BUFLEN;
	struct sockaddr_nl addr;
	struct nlmsghdr *nh;
	struct ifinfomsg *ifinfo;
	struct rtattr *attr;

	fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &len, sizeof(len));
	memset(&addr, 0, sizeof(addr));
	addr.nl_family = AF_NETLINK;
	addr.nl_groups = RTNLGRP_LINK;
	bind(fd, (struct sockaddr *)&addr, sizeof(addr));
	retval = read(fd, buf, BUFLEN);
	printf("retval = %d \n", retval);
	while ((retval = read(fd, buf, BUFLEN)) > 0) {
		for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, retval); nh = NLMSG_NEXT(nh, retval)) {
			if (nh->nlmsg_type == NLMSG_DONE)
				break;
			else if (nh->nlmsg_type == NLMSG_ERROR)
				return;
			else if (nh->nlmsg_type != RTM_NEWLINK)
				continue;
			ifinfo = NLMSG_DATA(nh);
			printf("%u: %s", ifinfo->ifi_index, (ifinfo->ifi_flags & IFF_LOWER_UP) ? "up" : "down");
			attr = (struct rtattr *)(((char *)nh) + NLMSG_SPACE(sizeof(*ifinfo)));
			len = nh->nlmsg_len - NLMSG_SPACE(sizeof(*ifinfo));
			for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
				if (attr->rta_type == IFLA_IFNAME) {
					printf(" %s", (char *)RTA_DATA(attr));
					break;
				}
			}
			printf("\n");
		}
	}

	return 0;
}

Guess you like

Origin blog.csdn.net/jiazhen/article/details/130113692