You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

跨平台网络接口枚举问询:GLib/GIO是否提供对应跨平台层?

用GLib/GIO实现跨平台网络接口枚举

既然你已经在大量使用GLib/GIO,那完全不用纠结原生API还是自己折腾跨平台层——GIO已经为你封装好了一套完美的跨平台网络接口枚举方案,直接用就行,完全兼容Linux和MinGW64环境,还能轻松拿到IPv4/IPv6地址及子网掩码。

核心优势

  • 无缝集成你现有GLib/GIO代码,不用写一堆#ifdef分支处理Linux和Windows的底层差异
  • 直接封装了接口的所有关键信息:名称、状态、IPv4/IPv6地址、子网掩码(前缀长度转掩码也有现成方法)
  • 维护成本低,GLib官方会处理不同系统的API变更,你不用自己跟进

代码示例

下面是一个完整的示例,能枚举所有网络接口的IPv4/IPv6地址和子网掩码:

#include <gio/gio.h>

int main(int argc, char *argv[]) {
    // 初始化GLib
    g_type_init();

    // 获取默认的网络监视器
    GNetworkMonitor *monitor = g_network_monitor_get_default();
    // 获取所有网络接口列表
    GList *interfaces = g_network_monitor_get_network_interfaces(monitor);

    g_print("枚举本地网络接口:\n");
    g_print("====================================\n");

    // 遍历每个接口
    for (GList *l = interfaces; l != NULL; l = l->next) {
        GNetworkInterface *iface = G_NETWORK_INTERFACE(l->data);
        const gchar *iface_name = g_network_interface_get_name(iface);
        const gchar *iface_display = g_network_interface_get_display_name(iface);

        g_print("接口名称: %s | 显示名称: %s\n", iface_name, iface_display);

        // 获取接口的所有地址(带子网掩码)
        GList *addresses = g_network_interface_get_addresses(iface);
        for (GList *a = addresses; a != NULL; a = a->next) {
            GInetAddressMask *mask = G_INET_ADDRESS_MASK(a->data);
            GInetAddress *addr = g_inet_address_mask_get_address(mask);
            gint prefix = g_inet_address_mask_get_prefix(mask);

            // 区分IPv4和IPv6
            if (g_inet_address_get_family(addr) == G_SOCKET_FAMILY_IPV4) {
                g_print("  IPv4地址: %s/%d (子网掩码: %s)\n",
                        g_inet_address_to_string(addr),
                        prefix,
                        g_inet_address_mask_to_string(mask));
            } else if (g_inet_address_get_family(addr) == G_SOCKET_FAMILY_IPV6) {
                g_print("  IPv6地址: %s/%d (子网前缀: %s)\n",
                        g_inet_address_to_string(addr),
                        prefix,
                        g_inet_address_mask_to_string(mask));
            }
        }

        // 清理地址列表
        g_list_free_full(addresses, g_object_unref);
        g_print("------------------------------------\n");
    }

    // 清理接口列表
    g_list_free_full(interfaces, g_object_unref);
    g_object_unref(monitor);

    return 0;
}

编译与运行

  • Linux:确保安装了GLib/GIO开发包,用以下命令编译:
    gcc -o enum_interfaces enum_interfaces.c `pkg-config --cflags --libs gio-2.0`
    
  • MinGW64:先安装MinGW版本的GLib/GIO(比如通过MSYS2的mingw-w64-x86_64-glib2包),然后用同样的命令编译(注意在MSYS2的MinGW64 shell中执行)。

关键API说明

  • g_network_monitor_get_default():获取系统默认的网络监视器实例,是入口点
  • g_network_monitor_get_network_interfaces():返回所有活跃(或已配置)的网络接口列表,每个元素是GNetworkInterface对象
  • g_network_interface_get_addresses():返回接口的所有地址条目,每个条目是GInetAddressMask——这个类直接封装了IP地址子网前缀长度,不用自己计算掩码
  • g_inet_address_mask_to_string():直接生成带掩码的字符串(比如192.168.1.100/242001:db8::1/64),如果需要单独的掩码字符串,也可以通过前缀长度计算(GIO也提供了相关工具函数)

对比原生API的好处

如果你自己用getifaddrs(Linux)和GetAdaptersAddresses(Windows),需要处理:

  • 不同系统的结构体差异(比如ifaddrs vs IP_ADAPTER_ADDRESSES
  • IPv6地址的解析和格式化
  • 子网掩码的转换(Windows返回的是掩码数组,Linux返回的是前缀长度)
  • 大量的#ifdef分支代码

而用GIO的话,这些细节都被封装好了,你只需要专注于业务逻辑,代码可读性和可维护性高很多。

内容的提问来源于stack exchange,提问作者eudoxos

火山引擎 最新活动