如何在Linux中以编程方式检测IP地址更改? 是否有一种方法可以在C++中使用C++编程实现本地机上的IP地址变化? < P>一种方法是编写一个CRON作业,其中包含对GethOST函数库函数的调用。如果使用gethostbyname(),则可以比较h_addr_list的返回值。请看男人的名字

如何在Linux中以编程方式检测IP地址更改? 是否有一种方法可以在C++中使用C++编程实现本地机上的IP地址变化? < P>一种方法是编写一个CRON作业,其中包含对GethOST函数库函数的调用。如果使用gethostbyname(),则可以比较h_addr_list的返回值。请看男人的名字,c++,linux,C++,Linux,如果您想在程序中执行此操作,请生成一个执行相同操作的pthread,然后在任意时间段内休眠。无论如何都不容易。每个Linux发行版使用不同的位置来存储IP地址等(如果您考虑其他UNIX变种,则会有更多的变化)。例如,您可以使用/sbin/ifconfig来获取接口的IP地址,但您甚至无法确定是否可以在此处找到它,或者根本无法找到它,等等 此外,如果您有该可执行文件,则必须设置一个线程来调用它,以获取给定时间段(例如5秒)的数据,并解释输出。它可能会有所不同,例如,如果你有桥梁等,也就是说,这并不

如果您想在程序中执行此操作,请生成一个执行相同操作的pthread,然后在任意时间段内休眠。

无论如何都不容易。每个Linux发行版使用不同的位置来存储IP地址等(如果您考虑其他UNIX变种,则会有更多的变化)。例如,您可以使用
/sbin/ifconfig
来获取接口的IP地址,但您甚至无法确定是否可以在此处找到它,或者根本无法找到它,等等

此外,如果您有该可执行文件,则必须设置一个线程来调用它,以获取给定时间段(例如5秒)的数据,并解释输出。它可能会有所不同,例如,如果你有桥梁等,也就是说,这并不容易


我想到的一个解决方案是,如果你有机会使用GNOME或其他广泛发行的KDE,你可以依赖它们提供的消息/信息。例如,
NetworkManager
在设备更改时向输出信号。您必须为这些信号实现侦听器。信息(目前不起作用,因此这里有一个示例)。当添加新接口或其中一个更改IP地址时,请注意不同的消息。这是我现在能想到的最好的方法。

如果您的用户使用NetworkManager,您可以通过D-Bus轮询NetworkManager.Connection.Active和NetworkManager.IP4Config,以获得确定此信息的更交叉分布方式。

在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”替换为您正在查看的接口。您现在需要做的就是轮询更改。

如果安装了iproute2,并且您使用的是2.6内核

/sbin/ip monitor
将本地接口状态和地址的更改输出到标准输出。你的程序可以读取这个


您还可以使用与iproute2工具相同的低级机制(我认为它是一个netlink套接字)。

来自rtnetlink的手册页:

描述


Rtnetlink允许读取和更改内核的路由表。它在内核中用于不同子系统之间的通信,尽管这里没有记录这种用法,并且用于与用户空间程序的通信。网络路由、ip地址、链路参数、邻居设置、排队规则、流量类别和数据包分类器都可以通过NETLINK_路由套接字进行控制。它基于netlink消息,请参阅netlink(7)了解更多信息。

ste建议使用ioctl SIOCGIFADDR过去在技术上是正确的,但不幸的是,对于现代Linux系统来说,它是不可靠的,因为一个接口可以有多个地址,而不使用子接口(例如eth0:1)就像现在已经过时的ifconfig一样

您的最佳选择是使用GetIFADRS(3),它来自glibc 2.3:


不幸的是,这有点低效(你会得到一个所有接口上所有地址的链接列表,需要反复查找你感兴趣的地址),但在大多数情况下,你可能不会每分钟检查一次,这样开销就可以忍受了。

给你。。这不需要投票

它只侦听RTM_NEWADDR,但如果需要,它应该很容易更改以支持RTM_DELADDR

#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <net/if.h>

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) {
                        char name[IFNAMSIZ];
                        if_indextoname(ifa->ifa_index, name);
                        char ip[INET_ADDRSTRLEN];
                        inet_ntop(AF_INET, RTA_DATA(rth), ip, sizeof(ip));
                        printf("interface %s ip: %s\n", name, ip);
                    }
                    rth = RTA_NEXT(rth, rtl);
                }
            }
            nlh = NLMSG_NEXT(nlh, len);
        }
    }
    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
int
main()
{
结构sockaddr_nl addr;
内特袜子,蓝;
字符缓冲区[4096];
结构nlmsghdr*nlh;
if((sock=socket(PF_NETLINK,sock_RAW,NETLINK_ROUTE))=-1){
perror(“无法打开NETLINK_路由套接字”);
返回1;
}
memset(&addr,0,sizeof(addr));
addr.nl_family=AF_NETLINK;
addr.nl_groups=RTMGRP_IPV4_IFADDR;
if(绑定(sock,(struct sockaddr*)&addr,sizeof(addr))=-1){
佩罗(“无法绑定”);
返回1;
}
nlh=(结构nlmsghdr*)缓冲区;
而((len=recv(sock,nlh,4096,0))>0){
while((NLMSG_OK(nlh,len))&&(nlh->NLMSG_type!=NLMSG_DONE)){
如果(nlh->nlmsg_type==RTM_NEWADDR){
结构ifaddrmsg*ifa=(结构ifaddrmsg*)NLMSG_数据(nlh);
结构rtattr*rth=IFA_RTA(IFA);
int rtl=IFA_有效载荷(nlh);
而(rtl和RTA_OK(rth,rtl)){
如果(rth->rta\U类型==IFA\U本地){
字符名[IFNAMSIZ];
如果索引名(ifa->ifa\U索引,名称);
字符ip[INET_ADDRSTRLEN];
inet_ntop(AF_inet、RTA_数据(rth)、ip、sizeof(ip));
printf(“接口%s ip:%s\n”,名称,ip);
}
rth=RTA_NEXT(rth,rtl);
}
}
nlh=NLMSG_NEXT(nlh,len);
}
}
返回0;
}

用C完成测试示例,并在单独的线程中监视通知:

#include <sys/socket.h> // AF_INET, socket(), bind()
#include <ifaddrs.h> // struct ifaddrs, getifaddrs()
#include <netinet/in.h> // struct sockaddr_in
#include <arpa/inet.h> // inet_ntoa(), htonl()
#include <net/if.h> // if_indextoname()
#include <pthread.h>
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <stdbool.h>

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;
}
#包括//AF\u INET、socket()、bind()
#包括//struct ifaddrs,getifaddrs()
#在中包含//结构sockaddr\u
#包括//inet_ntoa(),htonl()
#包括//if\u索引名称()
#包括
#包括
#包括
#包括
#包括
类型定义枚举{
IP地址,
IP地址删除
}ip地址变更通知类型;
typedef void(*ip地址更改通知回调)(ip地址更改通知类型,uint32 ip地址,void*用户数据);
静态int ip地址更改通知套接字=-1;
静态pthread\u t ip\u地址\u更改\u通知\u线程;
静态ip地址更改通知回调ip地址更改通知回调;
静态无效*ip地址更改通知回调用户数据;
无效*ip地址更改通知工作
#include <netlink/netlink.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <arpa/inet.h>
#include <iostream>

static char ip4Addr[INET_ADDRSTRLEN];

static int parseAddress(struct nlmsghdr *hdr)
{
    std::cout << "parseAddress" << std::endl;

    struct ifaddrmsg *iface = (struct ifaddrmsg *)nlmsg_data(hdr);

    struct nlattr *attrs[IFA_MAX + 1];

    if (nlmsg_parse(hdr, sizeof(struct ifaddrmsg), attrs, IFA_MAX, nullptr) < 0)
    {
        std::cerr << "problem parsing Netlink response" << std::endl;
        return -1;
    }

    if (attrs[IFA_ADDRESS] == nullptr)
    {
        std::cerr << "Address Never Received "
                  << std::endl;
        return -1;
    }

    inet_ntop(iface->ifa_family, nla_data(attrs[IFA_ADDRESS]), ip4Addr, sizeof(ip4Addr));

    if ((hdr->nlmsg_type == RTM_NEWADDR) && (iface->ifa_family == AF_INET))
    {
        std::cout << "IPv4 Address added : " << ip4Addr << std::endl;
    }

    if ((hdr->nlmsg_type == RTM_DELADDR) && (iface->ifa_family == AF_INET))
    {
        std::cout << "IPv4 Address deleted : " << ip4Addr << std::endl;
    }
    return 0;
}

static int parseLink(struct nlmsghdr *hdr)
{
    std::cout << "parseLink" << std::endl;
    struct ifinfomsg *iface = (struct ifinfomsg *)nlmsg_data(hdr);

    struct nlattr *attrs[IFLA_MAX + 1];

    if (nlmsg_parse(hdr, sizeof(struct ifinfomsg), attrs, IFLA_MAX, nullptr) < 0)
    {
        std::cerr << "problem parsing Netlink response" << std::endl;
        return -1;
    }

    if (attrs[IFLA_IFNAME] != nullptr)
    {
        if (hdr->nlmsg_type == RTM_NEWLINK)
        {
            std::cout << (char *)nla_data(attrs[IFLA_IFNAME]) << std::endl;
        }
        else if (hdr->nlmsg_type == RTM_DELLINK)
        {
            std::cout << (char *)nla_data(attrs[IFLA_IFNAME]) << std::endl;
        }
    }
    return 0;
}

static int receiveNewMsg(struct nl_msg *msg, void *arg)
{
    struct nlmsghdr *nlh = nlmsg_hdr(msg);
    int len = nlh->nlmsg_len;
    int type = nlh->nlmsg_type;
    while (nlmsg_ok(nlh, len))
    {
        if (type != RTM_NEWLINK && type != RTM_DELLINK && type != RTM_NEWADDR && type != RTM_DELADDR)
        {
            if (nlh->nlmsg_type == NLMSG_DONE)
            {
                std::cout << "message complete" << std::endl;
            }
            nlh = nlmsg_next(nlh, &len);
            continue;
        }
        if ((nlh->nlmsg_type == RTM_NEWLINK) || (nlh->nlmsg_type == RTM_DELLINK))
        {
            parseLink(nlh);
        }
        if ((nlh->nlmsg_type == RTM_NEWADDR) || (nlh->nlmsg_type == RTM_DELADDR))
        {
            parseAddress(nlh);
        }
        nlh = nlmsg_next(nlh, &len);
    }
    return 1;
}

int main(int argc, char const *argv[])
{
    struct nl_sock *sk;

    /* Allocate a new socket */
    sk = nl_socket_alloc();

    /*
    * Notifications do not use sequence numbers, disable sequence number checking.
    */
    nl_socket_disable_seq_check(sk);

    /*
    * Define a callback function, which will be called for each notification received
    */
    nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, receiveNewMsg, nullptr);
    nl_socket_modify_cb(sk, NL_CB_FINISH, NL_CB_CUSTOM, receiveNewMsg, nullptr);

    /* Connect to routing netlink protocol */
    nl_connect(sk, NETLINK_ROUTE);

    /* Subscribe to link notifications group */
    nl_socket_add_memberships(sk, RTNLGRP_LINK, 0);
    nl_socket_add_memberships(sk, RTNLGRP_IPV4_IFADDR, 0);

    /*
    * Start receiving messages. The function nl_recvmsgs_default() will block
    * until one or more netlink messages (notification) are received which
    * will be passed on to my_func().
    */

    while (1)
        nl_recvmsgs_default(sk);

    return 0;
}