项目介绍
计算机中一个字节共有256中,即ascii码表,而ascii码表的128~256之间的值是不可见的字符,对于一些只能支持可见字符的协议,如果传输二进制文件是无法实现的,因此就有了base64编码格式,base64编码格式能将所有的二进制数据,都转换为可显示的字符。
项目目标
实现一个在线的base64转换工具,支持文本的base64的可逆转与图片base64转换
base64编码原理
base64使用64个字符来对二进制数据进行编码
编码过程
Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3*8 = 4*6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。
关于这个编码的规则:
①.把3个字节变成4个字节。
②每76个字符加一个换行符。
③.最后的结束符也要处理。
也就是说将每三个字节转换为可现实的四个字节
注意:将每3个字节作为一组变成4个显示的字符,在这其中也会遇到一些问题,如果字符串的个数不能被3整除,那么也就意味着最后有1个或者2个字节,先使用0字节值在末尾补足,使其能够被3整除,然后在进行base64编码,在编码后的base64文本后加上1个或2个=号,表示补足的字节数
string Base64:: Encode(const string& strData)
{
string strEncode;
// 编码表
string strEncodeTable("ABCDEFGHIGKLMNOPQRSTUVWXYZabcdefhkigklmnopqrstuvwxyz0123456789+/");
unsigned char temp[4];
size_t index = 0;
for(size_t i = 0; i < strData.size() / 3; ++i )
{
int lineLength = 0;
temp[1] = strData[index++];
temp[2] = strData[index++];
temp[3] = strData[index++];
// 第一个字节的高6位
strEncode += strEncodeTable[temp[1]>>2];
// 第一个字节的低2位和第二个字节的高4位
strEncode += strEncodeTable[(temp[1]<<4 | temp[2] >> 4)&0x3F];
// 第二个字节的低4位和第三个字节的高2位
strEncode +=strEncodeTable[(temp[2] <<2 | temp[3] >> 6)& 0x3F];
// 第三个字节的低6位
strEncode +=strEncodeTable[temp[3]&0x3F];
lineLength += 4;
if( 76 == lineLength)
{
strEncode +="\r\n";
lineLength = 0;
}
}
size_t mod = strData.size() % 3;
// 剩余一个字节
if(1 == mod)
{
temp[1] = strData[index++];
// 第一个字节的高6位
strEncode += strEncodeTable[temp[1]>>2];
// 第一个字节的低2位
strEncode += strEncodeTable[(temp[1]&0x03)<<4];
strEncode +="==";
}
else if(2 == mod)
{
temp[1] = strData[index++];
temp[2] = strData[index++];
// 第一个字节的高6位
strEncode += strEncodeTable[temp[1]>>2];
//第一字节的低2位和第二个字节的高4位
strEncode += strEncodeTable[(temp[1]<<4 | temp[2] >> 4)&0x3F];
//第二个字节的低4位
strEncode+= strEncodeTable[(temp[2] << 2)&0x3F];
strEncode += "=";
}
return strEncode;
}
解码过程
解码过程和编码过程是可逆的,将base64编码过程的结果4个为一组转换为3个字节
为了快速的解码也可以构建一个解码表,以每个编码的的ascii码 值作为解码表的下标,到解码表中找到该编码在编码表中的下标,对于每个下标取其低6位,构成24个比特位,即:
base64[0]取其低6位,存储到一个整形的第18~23比特位置---->base64[0]<<18
base64[1]取其低6位,存储到一个整形的第12~17比特位置---->base64[1]<<12
base64[2]取其低6位,存储到一个整形的第11~06比特位置---->base64[2]<<6
base64[3]取其低6位,存储到一个整形的第0~5比特位置---->base64[3]
然后依次取该整形的低三个字节,即解码后的结果。
string Base64::Decode(const string& strData)
{
string strDecode;
// 为了快速解码,构建解码表
// base64编码主要使用:A~Z a~z '0'~'9' '+' '/'
// 编码的时候,是每6个比特位构成十进制数据,在编码表中找到对应的字节
// 解码时:以每个字符ASCII码作为数组的下标,取到该可显字符对应编码表中的下标
// 编码表中存储的是:每个可显字符在编码表中的下标
// 比如:A--->0 B--->1 即:数组的65号位置存储0,66号位置存储的是1
const char DecodeTable[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
62, // '+'
0, 0, 0,
63, // '/'
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // '0'-'9'
0, 0, 0, 0, 0, 0, 0,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // 'A'-'Z'
0, 0, 0, 0, 0, 0,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // 'a'-'z'
};
size_t value = 0; // 用来保存解码的4组6个比特位 --- 总共24个比特位
size_t index = 0;
while(index < strData.size())
{
// 注意 base编码时一行最多放76个字符,超过就放置下一行
if(strData[index] != '\r' && strData[index+1] != '\n')
{
// 一行没有解码完毕
//解析第一个编码-----以该编码作为解码表的下标,到解码表中找到该编码在编码表中的下标
value = DecodeTable[strData[index++]] << 18;
//解析第二个
value += DecodeTable[strData[index++]] <<12;
strDecode+= (value >>16)&0xFF;
if(strData[index] != '=')
{
//解析第三个编码
value+= DecodeTable[strData[index++]] << 6;
strDecode += (value>>8)&0xFF;
if(strData[index] != '=') //
{
//解析第四个编码
value += DecodeTable[strData[index++]];
strDecode +=(value &0xFF);
}
else
break;
}
else
break;
}
else
{
//解码来到该行的末尾
//跳过/r/n
index+=2;
}
}
return strDecode;
}
服务端与客户端的搭建
httplib的使用,在项目工程目录下添加httplib文件
httplib的应用流程
1.实例化一个Serve对象
2.在Serve对象中注册请求路由-----传入请求的资源路径以及一个回调函数(回调函数就是请求的处理函数-自己实现)
3.开始搭建一个服务器开始监听
4.一旦服务器接收到对应资源路径的请求,就会在Serve对象的请求路由信息中找到具体对应的处理函数进行执行,完成请求