报头压缩-ROHC报头压缩程序改进

序言

本文尝试在上一篇文章http://blog.csdn.net/baidu_35692628/article/details/72848022示例的基础上进行改进,程序编译运行与示例中一致。

  • 原程序实现的功能如下:

    • 生成单个定长的IP数据包
    • 创建/初始化/配置ROHC压缩器并添加压缩类
    • 单个IP数据包压缩并输出对应ROHC数据包
  • 改进后的ROHC程序实现的功能如下:

    • 自生成变长的多个UDP/IP数据包(添加IP校验和)
    • 创建/初始化/配置ROHC压缩器并添加多个压缩类
    • 多个UDP/IP数据包压缩并输出对应ROHC数据包
    • 计算不同数量不同包长下的ROHC压缩率

示例程序中使用到的函数功能总结如下:

rohc_init_buf_empty()        //将rohc_buf结构体数据部分初始化

rohc_comp_new2()             //创建压缩器

rohc_comp_enable_profile()   //压缩类设置profile-enable

rohc_buf_data()              //获取data缓存的位置

rohc_buf_data_at()           //获取给定偏离值offset的data缓存位置

rohc_buf_append()            //在已有数据之后再添加一定长度数据,同时改变原data长度值

rohc_compress4()             //压缩函数

rohc_comp_free()             //释放压缩器资源



以下逐个部分介绍具体的实现

1. UDP/IP数据包参数设置

  • (1) 定义多个存储UDP/IP/ROHC数据包的结构体指针数组
    • 结构体指针数据类型为系统自带类型
struct rohc_buf
{
    struct rohc_ts time;    //数据时间戳
    uint8_t *data;          //data缓存
    size_t max_len;         //缓存的最大长度
    size_t offset;          //data起始位置偏离值
    size_t len;             //data长度
}
/* IP数据包净荷 */
//==================
char *FAKE_PAYLOAD[PKT_NUM];
int pktNum = 0;

for (pktNum = 0; pktNum < PKT_NUM; pktNum++)                    //每个包长度相同,内容不同
{
    int str_len = 472;                          //IP净荷长度;for IP
    FAKE_PAYLOAD[pktNum] = (char *)malloc(sizeof(char) * BUFFER_SIZE);
    FAKE_PAYLOAD[pktNum] = randstr(FAKE_PAYLOAD[pktNum], str_len);
}
/* 随机字符串生成函数 */
//====================
char *randstr(char *dest, int n)
{
    int i,randnum;
    char eleString[63] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    for (i = 0; i < n; i++)
    {
        srand(time(NULL));                    //以当前时间来设置随机数种子
        usleep(100);                          //每隔100ms更新一次,保证随机种子不同,程序延时的主要来源
        randnum = rand()%62;                            //随机数生成函数
        *dest = eleString[randnum];                     //从字符串数组中取值
        dest++;
    }
    *dest = '\0';                                   //字符串结束符
    return (dest - n);                              //返回首地址
}   


  • (2) 修改struct rohc_buf元素初始化函数rohc_buf_init_empty为rohc_buf_init_empty_p
/* 报文结构体初始化函数 */
void rohc_buf_init_empty_p(struct rohc_buf *packet,uint8_t *buf,int len)
{
    packet -> time.sec = 0;
    packet -> time.nsec = 0;
    packet -> data = buf;                               //数据指针
    packet -> max_len = len;
    packet -> offset = 0;
    packet -> len = 0;
}
  • (3) 结构体指针数组初始化
    • 以IP包结构体指针数组为例,其他类似
uint8_t *ip_buffer_p;

/* 定义存储多个IP数据包的结构体指针数组 */
int array_num;
struct rohc_buf *IpArray[PKT_NUM];

for (array_num = 0; array_num < PKT_NUM; array_num++)
{
    IpArray[array_num] = (struct rohc_buf *)malloc(sizeof(struct rohc_buf));

    //每个结构体数组元素的缓存空间,暂定为定长包
    ip_buffer_p = (uint8_t *)malloc(sizeof(uint8_t) * BUFFER_SIZE);

    //BUFFER_SIZE大小可变
    rohc_buf_init_empty_p(IpArray[array_num], ip_buffer_p, BUFFER_SIZE);

    //ip_buffer_p指针删除后影响缓存数据赋值吗-不影响,每次分配的空间都未释放
    ip_buffer_p = NULL;
}
printf("size of IpArray is %ld \n",sizeof(IpArray));


2. 创建ROHC压缩器,多个压缩类使能profiles-enable

  • (1) 默认参数初始化压缩器ROHC
    • 压缩器类型声明与简单示例中一致
/* 用默认参数创建ROHC压缩器 */
printf("create the ROHC compressor\n");
compressor = rohc_comp_new2(ROHC_SMALL_CID, ROHC_SMALL_CID_MAX,gen_random_num, NULL);
if(compressor == NULL)
{
   fprintf(stderr, "failed create the ROHC compressor\n");
   return 1;
}
  • (2) 允许多个压缩类profiles
    • 添加UDP类,否则只能压缩IP包
/* 允许IP-only和UDP/IP */
if(!rohc_comp_enable_profiles(compressor, ROHC_PROFILE_IP, ROHC_PROFILE_UDP, -1))
{
    fprintf(stderr, "failed to enable the IP-only and IP/UDP-Lite profiles\n");
    rohc_comp_free(compressor);
    return 1;
}


3. UDP/IP数据包生成

  • (1) UDP数据包生成
/* 生成100个相同内容的UDP数据包 */

// UDP报头赋值
udp_header = (struct udphdr *)rohc_buf_data(*(UdpArray[count]));    //调用系统自带函数分配报头空间
udp_header -> source = htons(0x04d2);                   //源端口1234
udp_header -> dest = htons(0x04d3);                     //目的端口1235
(*(UdpArray[count])).len = 8;
udp_header -> len = htons((*(UdpArray[count])).len + strlen(FAKE_PAYLOAD[count]));  
udp_header -> check = 0x0000;         //此处UDP校验和使用全零不影响运行

// copy the payload just after the UDP header
// rohc_buf_append()函数会给rohc_buf结构体len字段赋值 = 数据包长度
rohc_buf_append(&(*(UdpArray[count])), (uint8_t *) FAKE_PAYLOAD[count], strlen(FAKE_PAYLOAD[count]));
  • (2) IP数据包生成
/* 生成100个相同内容的IPv4数据包 */

printf("build a fake IP packet every time\n");

/* IP报头赋值 */
ip_header = (struct iphdr *) rohc_buf_data(*(IpArray[count]));
ip_header-> version = 4;                /* we create an IP header version 4 */
ip_header-> ihl = 5;                    /* min. IPv4 header length (in 32-bit words) */
(*(IpArray[count])).len += ip_header->ihl * 4;
ip_header-> tos = 0;                    /* TOS is not important for the example */
ip_header-> tot_len = htons((*(IpArray[count])).len + ntohs(udp_header -> len));

printf("%ld\n",(*(IpArray[count])).len);
printf("%d\n",ntohs(udp_header -> len));
printf("%d\n", ntohs((ip_header->tot_len)));                //主机字节序和网络字节序

//记录IP或UDP/IP包长     
pkt_len[count] = ntohs((ip_header->tot_len));

ip_header-> id = 0;                     /* ID is not important for the example */
ip_header-> frag_off = 0;               /* No packet fragmentation */
ip_header-> ttl = 1;                    /* TTL is not important for the example */
ip_header-> protocol = 17;              /* protocol number */
// ip_header-> check = 0x3ba9; /* checksum */       //原程序直接赋值
ip_header-> saddr = htonl(0x01020304);          /* source address 1.2.3.4 */
ip_header-> daddr = htonl(0x05060708);          /* destination addr. 5.6.7.8 */
ip_header -> check = htons(IpCheckSum(ip_header,(*(IpArray[count])).len));  //字节序转换,否则出错

/* copy the payload just after the IP header */
rohc_buf_append(&(*(IpArray[count])), (uint8_t *) ((*(UdpArray[count])).data), ntohs(udp_header -> len));
  • 注:UDP/IP生成的几点说明
    • 1) 一开始遇到FAKE_PAYLOAD长度不能改变的问题,考虑了以下可能原因
      • 没有找到合适的profile。但是已经添加了UDP/IP profiles之后还是不能解决,profile添加UNCOMPRESSED类型能运行,但此时并未压缩数据包
      • 数组元素结构体成员数据类型。结构体内data缓存长度不够
      • 压缩函数参数设置不正确。
      • FAKE_PAYLOAD宏定义字符串长度受限。
      • 某个函数调用失败。检查之后发现压缩函数错误,压缩失败,深入rohc_compress4()函数检查未果
    • 2)但排查下来发现,FAKE_PAYLOAD不能改变是因为:
      • IP包校验和用了原程序中定长时计算出来的值,应重新计算IP校验和
      • IP校验和计算可参考我的另一篇文章:http://blog.csdn.net/baidu_35692628/article/details/72330676
    • 3)IP报头中的protocol字段应改为17,表示上层是UDP类型,否则压缩UDP数据包失败


4. ROHC压缩并输出显示

  • (1) 这部分仍然使用示例程序中的压缩函数
    • 循环压缩多个UDP/IP数据包
//形参:(压缩器,ip_packet缓存地址,rohc_packet缓存地址)
rohc_status = rohc_compress4(compressor, (*(IpArray[count])), RohcArray[count]);


5. 计算压缩率

  • 压缩率计算公式

    • 压缩字节数/原数据长度
  • 这里统计所有数据包的总长和压缩字节数进行计算


6. 程序编译运行

  • 编译运行程序与官网示例一致
    • gcc -o rohc_hello_world -Wall $(pkg-config rohc - -cflags) rohc_hello_world.c $(pkg-config rohc - -libs)


后记

  • 文章只是尝试修改了ROHC官网的简单示例,没有涉及压缩机制和压缩算法的改进

  • 压缩机制/算法改进需求还请参考完整的ROHC开发程序,github、codeforge等网站均可找到,建议在github寻找



Acknowledgements:
https://rohc-lib.org/presentation/getting-started/ (ROHC官网示例教程)
http://blog.csdn.net/u013793399/article/details/51537089 (ROHC协议库改造)

2017.07.18

你可能感兴趣的:(广播/通信标准/协议)