翻译: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;

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容

  • 大纲 一.Socket简介 二.BSD Socket编程准备 1.地址 2.端口 3.网络字节序 4.半相关与全相...
    VD2012阅读 2,258评论 0 5
  • 大纲 一.Socket简介 二.BSD Socket编程准备 1.地址 2.端口 3.网络字节序 4.半相关与全相...
    y角阅读 2,378评论 2 11
  • linux 内核定时器timer_list用法作者 codercjg 在 30 十月 2015, 2:27 下午 ...
    codercjg阅读 1,002评论 0 0
  • 网络中进程之间如何通信 为了方便大家获取源代码,可以移步这里,GitHub源代码 进程通信的概念最初来源于单机系统...
    batbattle阅读 14,145评论 1 5
  • 午后的阳光细碎而温暖,这个城市的秋天里,紫荆花开了又落,落了又开。然而时光并没有带走什么,只是在时光中消了...
    谁家的梅子阅读 232评论 1 3