翻译:How to detect IP address change programmatically in Linux?

Stack overflow地址:c++ - How to detect IP address change programmatically in Linux? - Stack Overflow


翻译:

有监测本机 IP地址修改的,使用C++在Linux上编程的方法吗?




Answers1:

在C语言中,我使用的获取当前IP的方法:

int s;

struct ifreq ifr = {};

s = socket(PF_INET, SOCK_DGRAM, 0);

strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));

if (ioctl(s, SIOCGIFADDR, &ifr) >= 0)

printf("%s\n",

  inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));

使用你感兴趣的网卡代替"eth0"。你需要做的就是轮询检查网卡IP是否有改变。


Answers2:

你来这里,这不需要轮询。

它只监听了 RTM_NEWADDR,但是它是很容易修改支持 RTM_DELADDR,如果你需要的话。

#include

#include

#include

#include

#include

#include

int main()

{

    struct sockaddr_nl addr;

    int sock, len;

    char buffer[4096];

    struct nlmsghdr *nlh;

    if ((sock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {

        perror("couldn't open NETLINK_ROUTE socket");

        return 1;

    }

    memset(&addr, 0, sizeof(addr));

    addr.nl_family = AF_NETLINK;

    addr.nl_groups = RTMGRP_IPV4_IFADDR;

    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {

        perror("couldn't bind");

        return 1;

    }

    nlh = (struct nlmsghdr *)buffer;

    while ((len = recv(sock, nlh, 4096, 0)) > 0) {

        while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE)) {

            if (nlh->nlmsg_type == RTM_NEWADDR) {

                struct ifaddrmsg *ifa = (struct ifaddrmsg *) NLMSG_DATA(nlh);

                struct rtattr *rth = IFA_RTA(ifa);

                int rtl = IFA_PAYLOAD(nlh);

                while (rtl && RTA_OK(rth, rtl)) {

                    if (rth->rta_type == IFA_LOCAL) {

                        uint32_t ipaddr = htonl(*((uint32_t *)RTA_DATA(rth)));

                        char name[IFNAMSIZ];

                        if_indextoname(ifa->ifa_index, name);

                        printf("%s is now %d.%d.%d.%d\n",

                              name,

                              (ipaddr >> 24) & 0xff,

                              (ipaddr >> 16) & 0xff,

                              (ipaddr >> 8) & 0xff,

                              ipaddr & 0xff);

                    }

                    rth = RTA_NEXT(rth, rtl);

                }

            }

            nlh = NLMSG_NEXT(nlh, len);

        }

    }

    return 0;

}


Answers3:

没有一种很容易的方式。每个Linux发行版使用不同的地方存储IP地址等(如果你考虑UNIX的变体将会有更多的版本)。例如,你可以使用,/sbin/ifconfig来获取接口的IP地址,但是你甚至不能确定你能找到它。

或者,给你一个可执行程序,你不得不建立一个线程在一定的时间周期内(比如5秒)获取数据,并中断进行输出。例如,如果你有桥梁,这可能会有所不同,但是这不是很容易的。

我想到的另一个解决方案是,如果你有机会使用 GNOME或者其他像 KDE的发行版本,你可以依赖它们提供的消息/信息。例如,NetworkManager输出一个信号到  DBUS standard bus,当设备改变时。你需要为这些信号添加一个监听器,监听这里的信息(不立即工作,在这里是一个缓存)。请注意,当一个新接口添加或者其中一个接口修改IP地址时会有不同的消息。这是我现在能想到的最好的方法。


Answers4:

如果你得用户使用 NetworkManager,你可以轮询 NetworkManager.Connection.Active和 NetworkManager.IP4Config通过 D-Bus,获取更多确定信息。


Answers5:

如果 iproute2安装了,你可以在 2.6版本的内核上这么做:

/sbin/ip monitor

如果本地网卡的状态和地址改变的话,会输出到控制台上。你的程序可以读这个信息。

你也可以使用其他类似 iproute2的低等级机制(我认为它是一个 netlink套接字)。


Answers6:

ste's建议使用 ioctl,使用 SIOCGIFADDR是技术正确的,不幸的是,它是不可行的对于现代的 Linux操作系统,这里一个网卡可以拥有多个地址在不使用子网卡的情况下(例如:eth0:1),就像现在已经过时的ifconfig所做的那样。

你最好使用 getifaddrs(3),这是 glibc2.3提供的: http://www.kernel.org/doc/man-pages/online/pages/man3/getifaddrs.3.html

不幸的是它效率不高(你会得到所有网卡的一个链表,并且不得不遍历它找到那个你想要的网卡),但是大多数情况下你检查它不超过一分钟一次,这是可以接受的。


Answers7:

一个方法是写一个计划任务,它包含调用 gethost family的相关库函数。如果你使用 gethostbyname()你可以比较返回值中的 h_addr_list。具体细节看 man gethostbyname。

如果你想要在你的程序中做这件事,创建一个线程做相同的事,然后睡眠一定的时间。


Answers8:

从 rtnetlink的man页引用:

描述:

Rtnetlink允许读取并修改内核路由表。它在内核中使用并在不同的子系统中通信,尽管它的用户空间通信的使用没有文档。网络路由,IP地址,link参数,相关设置,排队规则,流量类别和分组类别都可以被 NETLINK_ROUTE控制。它基于 netlink消息,看 netlink(7)获取更多的消息。


Answers9:

完整的C语言测试示例,并在不同的线程中进行通知:

#include // AF_INET, socket(), bind()

#include // struct ifaddrs, getifaddrs()

#include // struct sockaddr_in

#include // inet_ntoa(), htonl()

#include // if_indextoname()

#include

#include

#include

#include

#include

typedef enum {

    IP_ADDR_ADD,

    IP_ADDR_REMOVE

} ip_address_change_notification_type_t;

typedef void (*ip_address_change_notification_callback_t)(ip_address_change_notification_type_t type, uint32_t ipaddr, void *userdata);

static int ip_address_change_notification_socket = -1;

static pthread_t ip_address_change_notification_thread;

static ip_address_change_notification_callback_t ip_address_change_notification_callback;

static void *ip_address_change_notification_callback_userdata;

void *ip_address_change_notification_worker(void *arg)

{

    fprintf(stderr, "ip_address_change_notification_worker entered.\n");

    if (ip_address_change_notification_socket == -1) {

        goto done;

    }

    char buffer[4096];

    struct nlmsghdr *nlh = (struct nlmsghdr *)buffer;

    int len;

    while ((len = recv(ip_address_change_notification_socket, nlh, sizeof(buffer), 0)) > 0) {

        for (; (NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE); nlh = NLMSG_NEXT(nlh, len)) {

            if (nlh->nlmsg_type == RTM_NEWADDR) {

                fprintf(stderr, "Netlink: RTM_NEWADDR\n");

            } else if (nlh->nlmsg_type == RTM_DELADDR) {

                fprintf(stderr, "Netlink: RTM_DELADDR\n");

            } else {

                fprintf(stderr, "Netlink: nlmsg_type=%d\n", nlh->nlmsg_type);

                continue; // Some other kind of announcement.

            }

            struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(nlh);

            struct rtattr *rth = IFA_RTA(ifa);

            int rtl = IFA_PAYLOAD(nlh);

            for (; rtl && RTA_OK(rth, rtl); rth = RTA_NEXT(rth,rtl)) {

                char name[IFNAMSIZ];

                uint32_t ipaddr;

                if (rth->rta_type != IFA_LOCAL) continue;

                ipaddr = *((uint32_t *)RTA_DATA(rth)); // In network byte-order.

                fprintf(stderr, "Interface %s %s has IP address %s\n", if_indextoname(ifa->ifa_index, name), (nlh->nlmsg_type == RTM_NEWADDR ? "now" : "no longer"), inet_ntoa(*((struct in_addr *)&ipaddr)));

                if (ip_address_change_notification_callback) (*ip_address_change_notification_callback)((nlh->nlmsg_type == RTM_NEWADDR ? IP_ADDR_ADD : IP_ADDR_REMOVE), ipaddr, ip_address_change_notification_callback_userdata);

            }

        }

    }

done:

    fprintf(stderr, "ip_address_change_notification_worker exited.\n");

    return (NULL);

}

bool begin_ip_address_change_notifications(ip_address_change_notification_callback_t callback, void *userdata)

{

    if (ip_address_change_notification_socket != -1) return false;

    ip_address_change_notification_callback = callback;

    ip_address_change_notification_callback_userdata = userdata;

    if ((ip_address_change_notification_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {

        perror("begin_ip_address_change_notifications socket");

        return false;

    }

    struct sockaddr_nl addr;

    memset(&addr, 0, sizeof(addr));

    addr.nl_family = AF_NETLINK;

    addr.nl_groups = RTMGRP_IPV4_IFADDR;

    if (bind(ip_address_change_notification_socket, (struct sockaddr *)&addr, sizeof(addr)) == -1) {

        perror("begin_ip_address_change_notifications bind");

        goto bail;

    }

    pthread_attr_t attr;

    pthread_attr_init(&attr);

    pthread_attr_setdetachstate(&attr, 1); // Preclude the need to do pthread_join on the thread after it exits.

    int err = pthread_create(&ip_address_change_notification_thread, &attr, ip_address_change_notification_worker, NULL);

    pthread_attr_destroy(&attr);

    if (err != 0) {

        fprintf(stderr, "Error creating ip address change notification thread.\n");

        goto bail;

    }

    return (true);

bail:

    close(ip_address_change_notification_socket);

    ip_address_change_notification_socket = -1;

    ip_address_change_notification_callback = NULL;

    ip_address_change_notification_callback_userdata = NULL;

    return false;

}

void end_ip_address_change_notifications(void)

{

    if (ip_address_change_notification_socket == -1) return;

    pthread_cancel(ip_address_change_notification_thread);

    close(ip_address_change_notification_socket);

    ip_address_change_notification_socket = -1;

    ip_address_change_notification_callback = NULL;

    ip_address_change_notification_callback_userdata = NULL;

}

你可能感兴趣的:(翻译:How to detect IP address change programmatically in Linux?)