1.项目背景:

在计算机中一个字节共有256种,即ascii码表,而ascii码的128~255之间的值是不可见字符,对于一些只支持可见字符的协议,比如邮件传输协议(SMTP)只支持可见的ASCII字符的传递,如果要传输二进制文件,比如:图片、视 频是无法实现的,因此就有了base64编码格式,Base64编码格式对于所有二进制格式的数据,都可以转化为可显 示的字符base64的应用场景非常多,比如:

    1. 在网络上交换数据时,比如说从A地传递到B地,往往要经过多个路由设备,由于不同的设备对字符的处理方  式有一些不同,这样那些不可见字符就有可能被处理错误,不利于传输。
    2. http先以当中的key-value字段,必须进行url编码,不然出现的等号或者空格可能是解析失败
    3. 有些文本协议不支持可见字符传输,比如简单邮件传输协议(SMTP)
    4. 网页中内嵌简单图片

2.项目目标

实现一个在线的base64的转换工具,支持文本的base64编码以及base64的解码,以及图片base64的转换

3.整体框架:

采用B/S的模式

4.base64编码原理

base64编码之所以成为base64,是因为其使用64个字符来对二进制数据进行编码

采用对应的编码表:

4.1编码过程:

这是最重要的一步,也是核心的地方

具体编码过程如下:

  1. 将每三个字符作为一组,一共是24个二进制比特位
  2. 将这24个二进制比特位分为4组,每组有6个二进制比特位
  3. 在每组前面加两个00扩展成32个二进制位,即四个字节

说白了就是将每三个字节转变为上述表格中可显示的4个字节。具体如下:

字符串能被3整除,比如base64编码:Man

1.   "M""a""n"ASCII值分别是7797110,对应的二进制值是010011010110000101101110将它们连成一个24位的二进制字符串010011010110000101101110

2.      将这个24位的二进制字符串分成4组,每组6个二进制位:010011010110000101101110

3.      在每组前面加两个00,扩展成32个二进制位,即四个字节:000100110001011000000101

00101110。它们的十进制值分别是1922546

4.      根据上表,得到每个值对应Base64编码,即T,W,F,U

不能被3整除,比如base64编码:Lucy

如果要编码的字节数不能被3整除,最后会多出1个或2个字节,先使用0字节值在末尾补足,使其能够被3整    除,然后再进行Base64的编码。在编码后的Base64文本后加上一个或两个=号,代表补足的字节数。也就是  说,当最后剩余一个八位字节(1byte)时,最后一个6位的Base64字节块有四位是0值,最后附加上两个   等号;如果最后剩余两个八位字节(2byte)时,最后一个6位的base字节块有两位是0值,最后附加一个等 号。

注意:base64一行最多只能显示76个可显字符

缺陷:Base64将三个字节转化成四个字节,因此Base64编码后的文本,会比原文本大出三分之一左右

4.2解码过程

解码过程与编码过程是可逆的,对于一个base64的结果,只需每四个一组,将其转化为3个字节即可

采用对应的解码表:

假设对于base64结果:aGVsbG8=

每四个字节一组,以每个字符的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]

然后依次取该整形的低三个字节,即解码后的结果。

根据这样子的编码与解码,就能编写出base64的类与代码。

5.搭建服务端

5.1 使用cpp-httplib搭建服务器

本文使用cpp-httplib搭建http服务器,cpp-httplib是一个C++封装的跨平台的http库,借助该库可以快速在

windowslinux下搭建http服务器和客户端,使用非常简单,只需在项目中包含httplib.h头文件即可。

搭建http服务器的流程:

  1. 搭建tcp服务器
  2. 等待客户端连接请求
  3. 连接到来时,则创建线程/进程来处理这个连接

5.2Json使用介绍

JSON( JavaScript Object Notation)一种轻量级的数据交换格式.易于阅读和理解,也易于机器解析和生成.JSON采用独立于语言的文本格式,使用了类似于C语言家族的习惯(包括C,C++,C#,Java, JavaScript, Perl, Python).这些特性使得JSON成为理想的数据交换语言。

  1. json格式

对象

对象是一个无序的"'名称/'"集合.一个对象以“{”(左括号)开始,“}”(右括号)结束。每个名称跟一个“:”(冒号);“‘名称/之间使用“,”(逗号)分隔。

数组

数组是值(value)的有序集合。一个数组以“[”(左中括号)开始,“]”(右中括号)结束。值之间间使 “,”(逗号)分隔。

  1. vs2013下搭建json环境

2.设置json头文件加载路径

3.设置json lib库文件路径

4.包含json头文件和引入json 静态库文件

5.3http协议约定

1.文本转换为base64编码

2.图片转base64编码

6.客户端处理:

客户端请求以及收到服务响应之后,将转换结果更新到网页中,用THML语言实现。

 

 

以下是我编写的源代码;

base64类头文件

#pragma once

#include<string>
using namespace std;
class Base64
{
public:
	string Encode(const string& strdate);
	string Decode(const string& strdate);
};

base64类的实现

#include"Base64.h"
using namespace std;
string Base64::Encode(const string& strDate){
	string strEncode;
	string strEncodetable("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
	unsigned char temp[4];
	size_t index = 0;
	size_t lineLength = 0;
	for (size_t i = 0; i < strDate.size()/3; i++)
	{
		//三个字符一组来进行转换
		temp[1] = strDate[index++];
		temp[2] = strDate[index++];
		temp[3] = strDate[index++];
		//取一个第一个字节的高6位
		strEncode += strEncodetable[temp[1] >> 2];
		//取第一个字节的低2位,与第二个字节的高四位拼接
		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 = strDate.size() % 3;
	//模完剩余一个字节,补两个=号
	if (1 == mod){
		temp[1] = strDate[index++];
		strEncode += strEncodetable[ (temp[1] & 0xfc) >>2];
		strEncode += strEncodetable[(temp[1] & 0x03 )<< 4];
		strEncode += "==";
	}
	//摸完剩余两个字节,补一个=号
	else if (2 == mod){
		temp[1] = strDate[index++];
		temp[2] = strDate[index++];
		//取第一个字节的高6个比特位
		strEncode += strEncodetable[temp[1] >> 2];
		//取第一个字节的低2个比特位,与第二个字节的高4位
		strEncode += strEncodetable[(((temp[1] << 4) | (temp[2] >> 4)) & 0x3f)];
		//取第二个比特位的低4位
		strEncode += strEncodetable[(temp[2] & 0x0f) << 2];

		strEncode += "=";
	}
	return strEncode;
}
string Base64::Decode(const string& strDate){
	string strDecode;
	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;//用来保存解码的四组6个比特位---总共24个比特位
	size_t index = 0;
	while (index < strDate.size()){
		//base编码时一行能放置76个字符,超过76个字符,放置下一行
		if (strDate[index] != '\r' &&strDate[index+1] != '\n'){
			//一行没有解码完毕
			//解析第一个编码---->以该编码作为解码表的下标,到解码表找该编码在编码表的下标
			value=DecodeTable[strDate[index++]]<<18;
			//解析第二个编码
			value += DecodeTable[strDate[index++]] << 12;
			strDecode += ((value >> 16)&0xff);
			if (strDate[index] != '='){
				//解析第三个编码
				value += DecodeTable[strDate[index++]] << 6;
				strDecode += ((value >> 8)&0xff);
				if (strDate[index] != '='){
					//解析第四个编码
					value += DecodeTable[strDate[index++]];
					strDecode += (value&0xff);
				}
				else{
					break;
				}
			}
			else{
				break;
			}
		}
		else{
			//解码来到该行的末尾
			//跳过/r/n
			index += 2;
		}
	}
	return strDecode;
}

服务端的搭建以及对服务端的使用

#include"Base64.h"
#include<iostream>
#include"httplib.h"
#include"json.h"
#pragma comment(lib, ".\\..\\Debug\\json_vc71_libmtd.lib")
using namespace std;
//必须要有两个参数
//http请求
//http响应
void testjson(){
	Json::Value value;
	value["name"] = "peter";
	value["gender"] = "男";
	value["age"] = "18";
	int scores[] = { 70, 80, 90 };
	for (auto e : scores)
	{
		value["score"].append(e);
	}
	Json::StyledWriter sw;
	string strJsonData = sw.write(value);
	cout << strJsonData << endl;
	Json::Reader rd;
	Json::Value rdvalue;
	rd.parse(strJsonData,rdvalue);

}
void Str2base64(const httplib::Request &req,httplib::Response& rsp){
	//解析前端数据
	Json::Value value;
	Json::Reader rd;
	if (!rd.parse(req.body, value)){
		rsp.set_content("", "text/html");
		rsp.status = 500;
		return;
	}
	//将文本转换为base64
	Base64 base64;
	string strRst=base64.Encode(value["strtextdata"].asString());
	//先来进行序列化
	Json::StyledWriter sw;
	Json::Value wvalue;
	wvalue["base64Data"] = strRst;
	strRst = sw.write(wvalue);
	rsp.set_content(strRst, "text/html");
	rsp.status = 200;
}
void base642Str(const httplib::Request &req, httplib::Response& rsp){
	//解析前端数据
	Json::Value value;
	Json::Reader rd;
	if (!rd.parse(req.body, value)){
		rsp.set_content("", "text/html");
		rsp.status = 500;
		return;
	}
	//将文本转换为base64
	Base64 base64;
	string strRst = base64.Decode(value["base64data"].asString());
	//先来进行序列化
	Json::StyledWriter sw;
	Json::Value wvalue;
	wvalue["str"] = strRst;
	strRst = sw.write(wvalue);
	rsp.set_content(strRst, "text/html");
	rsp.status = 200;
}
int main()
{
	httplib::Server s;
	s.set_base_dir(".//..//Debug");
	s.Post("/str_2_base64", Str2base64);
	s.Post("/base64_2_str", base642Str);
	s.listen("127.0.0.1",9000);
	return 0;
}

下面是客户端的HTML的代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>base64在线转换工具</title>
		<style type="text/css">
			/*清除默认样式,定义网页选择样式*/
			*{
				margin: 0;
				padding: 0;
			}
			.select_menu{
				height: 30px;
				width: 800px;
				background-color: cornflowerblue;
				margin: 30px auto 3px;
			}
			.base64_text_content{
				height:600px;
				width: 800px;
				margin: 0 auto;
			}
			li{
				list-style:none;/*清除li前的标记*/
				cursor: pointer;/*当光标在li上,让光标按照小手鼠标样子进行显示*/
			}
			.select_menu li{
				float:left;
				height: 30px;
				width: 50%;
				text-align: center;
				color: white;
				font-weight: bold;
			}
			.select_menu li:hover{
				background-color: red;
			}
			
			.page_1{
				width: 100%;
				height: 100%;
				display: block;
			}
			.page_2{
				width: 100%;
				height: 100%;
				display: none;
			}
			.content_left{
				width:300px;
				height: 100%;
				float: left;
			}
			.content_mid{
				width:200px;
				height: 100%;
				background-color: aquamarine;
				float: left;
				text-align:center;
			}
			.content_right{
				width:300px;
				height: 100%;
				float: left;
			}
			.text{
				width:100%;
				height: 100%;
				resize: none;
			}
			.btn_op{
				background-color: aliceblue;
				display: block;
				margin: 30px auto;
			}
			.pictextarea{
				width:800px;
				height: 600px;
			}
		</style>
	</head>
	<body>
		<!--选择v具体操作功能菜单-->
		<div class="select_menu">
			<ul>
				<li onclick="select_op(true)">文本base64转换</li>
				<li onclick="select_op(false)">图片base64转换</li>
			</ul>
		</div>
		<!--具体显示 文本转64和图片转base64内容区-->
		<div class="base64_text_content">
			<div id="text2base64"class="page_1">
				
				
				<div class="content_left">
					<textarea id="strtext"class="text" >我是一个文本</textarea>
				</div>
				
				
				
				<div class="content_mid">
					<button class="btn_op"onclick="str2Base64()">文本转base64</button>
					<button class="btn_op"onclick="Base642str()">base64转文本</button>
				</div>
				
				
				
				<div class="content_right">
					<textarea id="base64Data"class="text" >我是一个文本</textarea>
				</div>
			</div>
			<div id="pic2base64"class="page_2">
				<form id="picData"  method="post" action="",enctype="multipart/form-data" style="float: left;">
					<input type="file" name="file" />
				</form>
				<button onclick="pic2Base64()">图片转base64</button>
				<p>base64图片数据</p>
				<textarea class="pictextarea"></textarea>
				<img src="img/1.jpg"/>
			</div>
		</div>
		
		
		<script src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script>
		<script>
			function select_op(op){
				if(op){
					document.getElementById("text2base64").style.display="block";	
				document.getElementById("pic2base64").style.display="none";
				}
				else{
					document.getElementById("pic2base64").style.display="block";
					document.getElementById("text2base64").style.display="none";
				}
			}
			function str2Base64(){
				//从网页中获取文本数据
				var strData=document.getElementById("strtext").value;
				//构造post请求,发送给服务器
				$.ajax({
					type:"POST",
					url:"/str_2_base64",
					data:JSON.stringify({"strtextdata":strData}),
					dataType:"json",
					success:function(result){
						//result保存的就是转换结果的json格式数据
						$("#base64Data").val(result["base64Data"]);
					},
					error:function(result){
						alert("str2base失败");
					}
				});
			}
			function Base642str(){
			var strData=document.getElementById("base64Data").value;
				//构造post请求,发送给服务器
				$.ajax({
					type:"POST",
					url:"/base64_2_str",
					data:JSON.stringify({"base64data":strData}),
					dataType:"json",
					success:function(result){
						//result保存的就是转换结果的json格式数据
						$("#strtext").val(result["str"]);
					},
					error:function(result){
						alert("str2base失败");
					}
				});
			}
			function pic2Base64(){
				//获取图片数据
			var strData=document.getElementById("base64Data").value;
			var formData=new FormData();
			var file=document.getElementById("picData").files[0];
			formData.append("strPicData",file);
				//构造post请求,发送给服务器
				$.ajax({
					type:"POST",
					url:"/pic_base64",
					data:formData,
					dataType:"json",
					success:function(result){
						//result保存的就是转换结果的json格式数据
						$("#strtext").val(result["str"]);
					},
					error:function(result){
						alert("str2base失败");
					}
				});
			}
		</script>
	</body>
</html>

以上就是项目的全部内容了。

谢谢观看:)

 

 

 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐