转义与数据通讯

在TCP通讯中,常需要添加一些特殊字节用作识别,但数据里面肯定有可能包含这些识别字节,一开始想到的是把数据里面的这些特殊字节替换为另一个字节,使特殊字节不出现(通常的转义算法转义后,被转义字符还是会出现在转义结果中的),一番折腾后走入了死胡同,始终无法全部的正确还原,再经过一番折腾才想到,其实可以把某几个字节序列用作识别,然后对这个组合里的每一个字节进行转义,这样转义后数据里就不会再出现识别用的字节序列。

注意,编程时写的斜杆转义是给编译器识别的,如果发送一个"\r\n"的字符串,实际发送的数据里回车换行并没有被转义。

还有一种处理方案,就是发送数据的base64字符串,然后以不在base64使用字符里的其他字符作为识别,但是这样会导致数据长度增加,平均增加33%左右。

转义与还原过程

// 转义
text.replace(escape, escape + escape);
text.replace(delimiter1, escape + delimiter1);
text.replace(delimiter2, escape + delimiter2); 

// 还原
text.replace(escape + delimiter2 , delimiter2); 
text.replace(escape + delimiter1 , delimiter1);
text.replace(escape + escape, escape);

其中escape为转义符号,delimiter1 、delimiter2为被转义字符,注意转义符号在替换中的顺序!

C语言的转义实现与测试(gcc -std=c99 -o escape escape.c)

#include <stdio.h>

//数据包分隔序列:0x03 0x02(也可以是0x02 0x03)
//这里先计算转义后长度,再转义
//可以预见:转义后最大长度也就两倍,所有也可以分配两倍大小的空间后直接转换,不外乎使用cpu与使用内存的平衡。

unsigned char esc = 0x1b; //转义符号
unsigned char d1 = 0x02; //转义字符1
unsigned char d2 = 0x03; //转义字符2


int getEscapeToLen(unsigned char data[], int len)
{
    int count = 0;
    for(int i = 0; i < len; i++){
        if(data[i] == esc || data[i] == d1 || data[i] == d2) count++;
    }
    return len + count;
}

int getEscapeOutLen(unsigned char data[], int len)
{
    int count = 0;
    for(int i = 0; i < len; i++){
        if(data[i] == esc && i + 1 < len)
        {
            if(data[i + 1] == esc || data[i + 1] == d1 || data[i + 1] == d2)
            {
                count++;
            }
            i++;
        }
    }
    return len - count;
}

int escapeTo(unsigned char data[], int len, unsigned char result[])
{
    int count = 0;
    for(int i = 0; i < len; i++){
        if(data[i] == esc || data[i] == d1 || data[i] == d2)
        {
            result[i + count] = esc;
            count++;
        }
        result[i + count] = data[i];
    }
    return count;
}

int escapeOut(unsigned char data[], int len, unsigned char result[])
{
    int count = 0;
    for(int i = 0; i < len; i++){
        if(data[i] == esc && i + 1 < len)
        {
            if(data[i + 1] == esc || data[i + 1] == d1 || data[i + 1] == d2)
            {
                count++;
            }
            else
            {
                result[i - count] = data[i];
            }
            i++;
        }
        result[i - count] = data[i];
    }
    return count;
}

void test(unsigned char data[], int dataLen)
{
    for(int i = 0; i < dataLen; i++)
    {
        printf("0x%02X ", data[i]);
    }
    printf("  ");

    int toLen = getEscapeToLen(data, dataLen);
    unsigned char toResult[toLen];
    int toCunnt = escapeTo(data, dataLen, toResult);

    for(int i = 0; i < 12; i++)
    {
        if(i < toLen)
        {
            printf("0x%02X ", toResult[i]);
        }
        else
        {
            printf("     ");
        }
    }
    printf("%d ", toCunnt);
    printf("  ");

    int outLen = getEscapeOutLen(toResult, toLen);
    unsigned char outResult[outLen];
    int outCount = escapeOut(toResult, toLen, outResult);

    for(int i = 0; i < outLen; i++)
    {
        printf("0x%02X ", outResult[i]);
    }
    printf("%d ", outCount);
    printf("  ");

    if(dataLen==outLen)
    {
        int hasErr = 0;
        for(int i = 0; i < dataLen; i++)
        {
            if(data[i] != outResult[i])
            {
                hasErr = 1;
            }
        }
        if(hasErr == 0)
        {
            printf("ok");
        }
    }

    printf("\n");
}

void main()
{
    unsigned char c[] = {0x02,0x03,0x1b,0xaa}; //前三个字节为转义字节,最后一个为数据代表,然后由它们构成6个字节长度的排列
    unsigned char data[6];
    for(int i = 0; i < 4; i++)
    {
        data[0] = c[i];
        for(int j = 0; j < 4; j++)
        {
            data[1] = c[j];
            for(int k = 0; k < 4; k++)
            {
                data[2] = c[k];
                for(int l = 0; l < 4; l++)
                {
                    data[3] = c[l];
                    for(int m = 0; m < 4; m++)
                    {
                        data[4] = c[m];
                        for(int n = 0; n < 4; n++)
                        {
                            data[5] = c[n];
                            test(data, 6);
                        }
                    }
                }
            }
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值