热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

网络编程之RoutingSockets(二)

1.sysctlOperations#include<sysparam.h>#include<syssysctl.h>intsysctl(int

1. sysctl Operations

#include 
#include 
int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen);
Returns: 0 if OK, −1 on error

这里写图片描述
  对于最基本的API操作,并不需要额外关注,注意name参数可能的选项搭配方式:
这里写图片描述

  UNP着重介绍了NET_RT_IFLIST,这里也看看该选项的解释:

  • returns information on all configured interfaces. If name[5] is nonzero, it is an interface index number, and only information on that interface is returned.
  • All the addresses assigned to each interface are also returned, and if name[3] is nonzero, only addresses for that address family are returned.
  • For each interface, one RTM_IFINFO message is returned, followed by one RTM_NEWADDR message for each address assigned to the interface. The RTM_IFINFO message is followed by one datalink socket address structure, and each RTM_NEWADDR message is followed by up to three socket address structures: the interface address, the network mask, and the broadcast address.

  上面的话总结一下就是如果sysctl都采用默认的选项,那么返回每个接口上每个地址的相关信息:网络地址,子网掩码,广播地址;因为可能某些接口绑定的不只一个地址,这种现象叫地址别名。如下图所示一种返回的数据结构情况:
这里写图片描述

2. 相对应的API修改

char * net_rt_iflist(int family, int flags, size_t *lenp)
{
    int mib[6];
    char *buf;
    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = family; /* only addresses of this family */
    mib[4] = NET_RT_IFLIST;
    mib[5] = flags; /* interface index or 0 */
    if (sysctl(mib, 6, NULL, lenp, NULL, 0) <0)
        return (NULL);
    if ( (buf = malloc(*lenp)) == NULL)
        return (NULL);
    if (sysctl(mib, 6, buf, lenp, NULL, 0) <0) {
        free(buf);
        return (NULL);
    }
    //第一次的调用sysctl是为了得到返回信息的大小
    return (buf);
}


struct ifi_info * get_ifi_info(int family, int doaliases)
{
    int flags;
    char *buf, *next, *lim;
    size_t len;
    struct if_msghdr *ifm;
    struct ifa_msghdr *ifam;
    struct sockaddr *sa, *rti_info[RTAX_MAX];
    struct sockaddr_dl *sdl;
    struct ifi_info *ifi, *ifisave, *ifihead, **ifipnext;
    buf = Net_rt_iflist(family, 0, &len);
    ifihead = NULL;
    ifipnext = &ifihead;
    lim = buf + len;
    //所有的返回信息都存储在buf中,且大小为len
    for (next = buf; next ifm_msglen) {
        ifm = (struct if_msghdr *) next;
        if (ifm->ifm_type == RTM_IFINFO) {
                //ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy)中获取接口的标志位,与这里进行对比下
            if (((flags = ifm->ifm_flags) & IFF_UP) == 0)
                continue; /* ignore if interface not up */
            sa = (struct sockaddr *) (ifm + 1);
            //ifm->ifm_addrs置位的相应信息填充rti_info数组
            get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
            if ( (sa = rti_info[RTAX_IFP]) != NULL) {
                ifi = Calloc(1, sizeof(struct ifi_info));
                *ifipnext = ifi; /* prev points to this new one */
                ifipnext = &ifi->ifi_next; /* ptr to next one goes here */
                ifi->ifi_flags = flags;
                if (sa->sa_family == AF_LINK) {
                    sdl = (struct sockaddr_dl *) sa;
                    ifi->ifi_index = sdl->sdl_index;
                    if (sdl->sdl_nlen > 0)
                        snprintf(ifi->ifi_name, IFI_NAME, "%*s",sdl->sdl_nlen, &sdl->sdl_data[0]);
                    else
                        snprintf(ifi->ifi_name, IFI_NAME, "index %d",sdl->sdl_index);
                    if ( (ifi->ifi_hlen = sdl->sdl_alen) > 0)
                        memcpy(ifi->ifi_haddr, LLADDR(sdl), min(IFI_HADDR, sdl->sdl_alen));
                }
            }
        } else if (ifm->ifm_type == RTM_NEWADDR) {
            //每次填充ifi结构体之前,先检查是否该地址是别名
            if (ifi->ifi_addr) { /* already have an IP addr for i/f */
                if (doaliases == 0)
                    continue;
                /* we have a new IP addr for existing interface */
                //直接copy相同的接口的其他成员信息,除了该地址
                ifisave = ifi;
                ifi = Calloc(1, sizeof(struct ifi_info));
                *ifipnext = ifi; /* prev points to this new one */
                ifipnext = &ifi->ifi_next; /* ptr to next one goes here */
                ifi->ifi_flags = ifisave->ifi_flags;
                ifi->ifi_index = ifisave->ifi_index;
                ifi->ifi_hlen = ifisave->ifi_hlen;
                memcpy(ifi->ifi_name, ifisave->ifi_name, IFI_NAME);
                memcpy(ifi->ifi_haddr, ifisave->ifi_haddr, IFI_HADDR);
            }
            ifam = (struct ifa_msghdr *) next;
            sa = (struct sockaddr *) (ifam + 1);
            get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
            if ( (sa = rti_info[RTAX_IFA]) != NULL) {
                ifi->ifi_addr = Calloc(1, sa->sa_len);
                memcpy(ifi->ifi_addr, sa, sa->sa_len);
            }
            if ((flags & IFF_BROADCAST) && (sa = rti_info[RTAX_BRD]) != NULL) {
                ifi->ifi_brdaddr = Calloc(1, sa->sa_len);
                memcpy(ifi->ifi_brdaddr, sa, sa->sa_len);
            }
            if ((flags & IFF_POINTOPOINT) &&(sa = rti_info[RTAX_BRD]) != NULL) {
                ifi->ifi_dstaddr = Calloc(1, sa->sa_len);
                memcpy(ifi->ifi_dstaddr, sa, sa->sa_len);
            }
        } else
            err_quit("unexpected message type %d", ifm->ifm_type);
    }
/* "ifihead" points to the first structure in the linked list */
    return (ifihead); /* ptr to first structure in linked list */
}

  特别强调上面程序一点:只有不同的接口或者该接口有多个地址才会调用修改链表的语句,来使当前ifi结构体添加到链表尾端。

3. Interface Name and Index Functions

#include 
unsigned int if_nametoindex(const char *ifname);
Returns: positive interface index if OK, 0 on error
char *if_indextoname(unsigned int ifindex, char *ifname);
Returns: pointer to interface name if OK, NULL on error
struct if_nameindex *if_nameindex(void);
Returns: non-null pointer if OK, NULL on error
void if_freenameindex(struct if_nameindex *ptr);

struct if_nameindex {
    unsigned int if_index; /* 1, 2, ... */
    char *if_name; /* null-terminated name: "le0", ... */
};

  从函数名字也能看出来该组API的用法,特别强调参数的用法:

  • The ifname argument points to a buffer of size IFNAMSIZ that the caller must allocate to hold the result, and this pointer is also the return value upon success.
  • if_nameindex returns a pointer to an array of if_nameindex structures. The final entry in this array contains a structure with an if_index of 0 and an if_name that is a null pointer. The memory for this array, along with the names pointed to by the array members, is dynamically obtained and is returned by calling if_freenameindex.

4. 最后

  该部分内容包括网络编程之ioctl Operations,并不是重点,但是也应该稍微了解下。系统提供了这样的接口及route或者arp等程序的作用机理。


推荐阅读
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文讨论了在Windows 8上安装gvim中插件时出现的错误加载问题。作者将EasyMotion插件放在了正确的位置,但加载时却出现了错误。作者提供了下载链接和之前放置插件的位置,并列出了出现的错误信息。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
  • 如何使用Python从工程图图像中提取底部的方法?
    本文介绍了使用Python从工程图图像中提取底部的方法。首先将输入图片转换为灰度图像,并进行高斯模糊和阈值处理。然后通过填充潜在的轮廓以及使用轮廓逼近和矩形核进行过滤,去除非矩形轮廓。最后通过查找轮廓并使用轮廓近似、宽高比和轮廓区域进行过滤,隔离所需的底部轮廓,并使用Numpy切片提取底部模板部分。 ... [详细]
author-avatar
水月琴轩_452
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有