由子网掩码字符串转换成长度前缀的代码示例

最近在进行的ONVIF任务,有一个接口是设置IP的,叫SetNetworkInterfaces,可以设置包括网络速率、双工、自动协商等功能,还可以改IP。但里面有子网掩码字段,只有一个叫PrefixLenght的,直译为前缀长度。具体如下:

IPv4 - optional; [IPv4NetworkInterfaceSetConfiguration]
IPv4 network interface configuration.
 Enabled - optional; [boolean]
             Indicates whether or not IPv4 is enabled.
Manual - optional, unbounded; [PrefixedIPv4Address]
             List of manually added IPv4 addresses.
 Address [IPv4Address]
                     IPv4 address
PrefixLength [int]
                     Prefix/submask length

PrefixLength就是子网掩码的长度。比如子网掩码为“255.255.0.0”,则PrefixLength为16。为了做转换,特意写了2个函数。

1、由子网掩码算出前缀长度

int ipv4_str2prefixlen(const char* ip_str)
{
    int ret = 0;
    unsigned int ip_num = 0;
    unsigned char c1,c2,c3,c4;
    int cnt = 0;

    ret = sscanf(ip_str, "%hhu.%hhu.%hhu.%hhu", &c1, &c2, &c3, &c4);
    ip_num = c1<<24 | c2<<16 | c3<<8 | c4;

    // fast...
    if (ip_num == 0xffffffff) return 32;
    if (ip_num == 0xffffff00) return 24;
    if (ip_num == 0xffff0000) return 16;
    if (ip_num == 0xff000000) return 6;

    // just in case
    for (int i = 0; i < 32; i++)
    {
        //unsigned int tmp = (ip_num<<i);
        //printf("%d tmp: %x\n", i+1, tmp);
        if ((ip_num<<i) & 0x80000000)
            cnt++;
        else
            break;
    }
    
    //printf("cnt: %d\n", cnt);
    return cnt;
}

2、由前缀长度算出子网掩码

int ipv4_prefixlen2str(int prefixlen, char* ip_str)
{
    char tmp[16] = {0};
    char* p = tmp;
    unsigned int ip_num = 0;


    if (ip_str == NULL) return -1;
    if (prefixlen > 32) return -1;


    // fast...
    if (prefixlen == 8) strcpy(ip_str, "255.0.0.0");
    if (prefixlen == 16) strcpy(ip_str, "255.255.0.0");
    if (prefixlen == 24) strcpy(ip_str, "255.255.255.0");
    if (prefixlen == 32) strcpy(ip_str, "255.255.255.255");


    // just in case
    for (int i = prefixlen, j = 31; i > 0; i--, j--)
    {
        //unsigned int tmp = (1<<j);
        //printf("%d tmp: %08x\n", i, tmp);
        ip_num += (1<<j);
    }
    //printf("ip_num: %08x\n", ip_num);
    sprintf(ip_str, "%hhu.%hhu.%hhu.%hhu", (ip_num>>24)&0xff, (ip_num>>16)&0xff, (ip_num>>8)&0xff, ip_num&0xff);


    return 0;
}
几点说明如下:

1、内部功能函数一般不作严格、详细的参数验证,比如IP的合法性没作检查。

2、一些常用的、已知的常识,应该优先使用,比如,我们知道“255.255.0.0”的前缀长度是16,则可以直接写出来,不再做转换。

3、最近搞ONVIF,真正认识到存储空间和运行时效率。在嵌入式中,flash有限,所以存储空间也要注意,用gsoap生成的ONVIF代码比较大,即使使用-O3优化并strip,也有10MB,真的很占空间。另外,有些功能模块可以统一在一处作参数合法性判断而不用每个函数都做。比如上面的示例代码就不用IP合法性判断,因此我调用之前已经做了,这样可以节省一些运行时的指令代码。不过,我们公司架构因为分层级关系,基本上经过review后的代码,每一层都有参数的检查。从效率上看,我依然坚持能省即省的原则。


李迟 2016.01.24 于加班回来晚饭前 (听说南宁青秀山下雪了,今天去加班的我的世界也开始下雪)

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,这是一个比较基础的络编程问题,下面是一份使用C语言编写的IPv6前缀长度转为码的程序: ```c #include <stdio.h> #include <stdint.h> #include <arpa/inet.h> #include <string.h> #include <netinet/in.h> int main(int argc, char **argv) { if (argc != 2) { printf("Usage: %s <prefix length>\n", argv[0]); return 1; } uint8_t prefix_len = atoi(argv[1]); if (prefix_len > 128) { printf("Invalid prefix length\n"); return 1; } struct in6_addr mask; memset(&mask, 0, sizeof(struct in6_addr)); uint8_t *p = mask.s6_addr; while (prefix_len >= 8) { *p++ = 0xff; prefix_len -= 8; } if (prefix_len > 0) { *p = (uint8_t)(0xff << (8 - prefix_len)); } char mask_str[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &mask, mask_str, INET6_ADDRSTRLEN); printf("Subnet mask: %s\n", mask_str); return 0; } ``` 这个程序的思路是先接收一个IPv6前缀长度作为命令行参数,然后根据前缀长度计算出对应的码。IPv6地址的长度为0到128,所以我们需要先判断输入的前缀长度是否合法。接下来,我们创建一个类型为struct in6_addr的变量mask,用于存储码,然后遍历前缀长度的每一位,将对应的字节设置为1。最后输出计算出的码即可。 需要注意的是,在IPv6地址中,码是一个128位的地址,因此我们需要使用结构体类型struct in6_addr来存储地址。同时,IPv6地址在络字节序中同样使用大端序(也就是高位字节在前),因此我们需要使用htonl()和ntohl()等函数将字节序转换络字节序或主机字节序,以确保程序在不同系统上的正确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值