安全传输平台项目——统一报文编解码一教师结构体编码
在学习安全传输平台项目总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
10-安全传输平台项目-第02天(统一报文编解码一教师结构体编码)
目录:
一、复习
1、项目架构图
2、启动数据库
二、安全传输平台项目
1、常见基础报文类型
2、BER报文编解码
3、指针充当函数返回值
4、统一报文编解码函数接口
5、教师结构体编码实现
6、解码教师结构体分析
7、教师结构体解码实现
8、内存释放
9、统一报文编解码函数接口
10、报文接口封装注意事项
一、复习
1、项目架构图:
2、启动数据库:
1. su - oracle
2. sqlplus /nolog show user;
3. connect /as sysdba show user;
4. startup select * from scott.dept;
5. quit;
3、启动TNS服务:
lsnrctl start
二、安全传输平台项目—统一报文编码组
1、常见基础报文类型
1)HTTP超文本传输协议
超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。1960年美国人Ted Nelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),这成为了HTTP超文本传输协议标准架构的发展根基。Ted Nelson组织协调万维网协会(World Wide Web Consortium)和互联网工程工作小组(Internet Engineering Task Force )共同合作研究,最终发布了一系列的RFC,其中著名的RFC 2616定义了HTTP 1.1。
举个例子:
#Request和Response的格式 Request格式: HTTP请求行 (请求)头 空行 可选的消息体 注:请求行和标题必须以<CR><LF> 作为结尾(也就是,回车然后换行)。空行内必须只有<CR><LF>而无其他空格。在HTTP/1.1 协议中,所有的请求头,除Host外,都是可选的。 实例: GET / HTTP/1.1 Host: gpcuster.cnblogs.com User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive If-Modified-Since: Mon, 25 May 2009 03:19:18 GMT Response格式: HTTP状态行 (应答)头 空行 可选的消息体 实例: HTTP/1.1 200 OK Cache-Control: private, max-age=30 Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Expires: Mon, 25 May 2009 03:20:33 GMT Last-Modified: Mon, 25 May 2009 03:20:03 GMT Vary: Accept-Encoding Server: Microsoft-IIS/7.0 X-AspNet-Version: 2.0.50727 X-Powered-By: ASP.NET Date: Mon, 25 May 2009 03:20:02 GMT Content-Length: 12173 消息体的内容(略)
2)HTML文本标记语言
HTML文本标记语言,即HTML(Hypertext Markup Language),是用于描述网页文档的一种标记语言。一个网页对应于一个HTML文件,HTML文件以.htm或.html为扩展名。可以使用任何能够生成TXT类型源文件的文本编辑来产生HTML文 件。 超文本标记语言标准的HTML文件都具有一个基本的整体结构,即HTML文件的开头与结尾标志和HTML的头部与实体2大部分。有3个双标记符用于页面整 体结构的确认。
HTML是一种规范,一种标准,它通过标记符号来标记要显示的网页中的各个部分。
http 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收 HTML页面的方法。1960年美国人Ted Nelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),这成为了HTTP超文本传输协议标准架构的发展根基。 Ted Nelson组织协调万维网协会(World Wide Web Consortium)和互联网工程工作小组(Internet Engineering Task Force )共同合作研究,最终发布了一系列的RFC,其中著名的RFC 2616定义了HTTP 1.1。
总结:HTML是超文本标记语言,HTTP是协议,HTML在HTTP协议上运行的;通过HTTP协议也可以传输声音、图像、数据。等等。
举个例子:
<html> <head> <title>Document name goes here</title> </head> <body> <a href="http://www.example.com/">This is a Link</a> <a href="http://www.example.com/"><img src="URL" alt="Alternate Text"></a> <a href="mailto:webmaster@example.com">Send e-mail</a>A named anchor: <a name="tips">Useful Tips Section</a> <a href="#tips">Jump to the Useful Tips Section</a> </body> </html>
3)XML可扩充标注语言
XML为Extensible Markup Language的缩写,即可扩充标注语言。它是由SGML所精简而来的一种通用标注语言,主要是要简化SGML烦杂的结构,强化HTML过于简单而不够严谨的语法。微软是XML技术的推动者之一,它希望能够建立一个可以为WWW 广泛使用语言环境,推动程序的兼容与协同,从而降低成本,刺激增长。
现有的XML主要应用在四个方面:一是应用于具有不同复杂格式的不同数据源间的交互;二是应用于大量运算负荷分布在客户端的情况,用户可以根据自己的需求选择和制作不同的应用程序以处理数据,而服务器只需发出同一个XML文件;三是应用于将同一数据以不同的形式表现出来;四是应用于网络代理对所取得的信息进行编辑、增减以适应个人用户的需要,形成具有个人特色的数据文件。
“XML最大的影响在于XML软件大量兴起:XML剖析器、XML程序语言库、XSLT处理器、XSL FO处理器、数据库接受XML——不只如此,还有网络浏览器也接受XML。”XML工作小组创始会员C.M. Sperberg-McQueen如是认为。也正因为如此,IBM、微软、SUN、惠普、Oracle等大公司纷纷进入这个市场。
而在XML最大应用之一的数据格式转换领域,Adobe、微软、Core都在各自相关的软件产品中充分利用了XML技术。以程序关联为特色的Office 2003更是将XML的格式转换特性发挥到了极致,以至于这个软件套装几乎成为了一个独立的数据系统。
举个例子:
<!DOCTYPE project [ <!ENTITY Common SYSTEM "common.xml"> %Common; ]> <!-- Bouncy Castle Build Configuration (midp) This is the JDK 1.1 specific build file. $RCSfile: jdk11.xml,v $ $Author: bouncy $ $Date: 2005/07/06 13:02:52 $ $Revision: 1.1.1.1 $ --> <project name="jdk11" default="init" basedir="."> <property environment="env" /> <property file="${env.CRYPTO_PROP}" /> <!-- Public callable targets --> <target name="clean" depends="common-clean" /> <target name="test" depends="common-test" /> <target name="dist" depends="common-dist" /> <target name="package" depends="common-package" /> <target name="compile" depends="init, local-compile" /> <target name="jdoc" depends="common-jdoc" /> <!-- include common targets, properties --> <property name="master.jdk" value="jdk11" /> &Common; <!-- ** Private properties --> <patternset id="jdk11.lw-compatibility" > <include name="java/**" /> </patternset> <patternset id="jdk11.jce-compatibility"> <include name="org/**" /> </patternset> <patternset id="jdk11.lw-extras" > <include name="org/bouncycastle/crypto/test/*.java" /> </patternset> <patternset id="orgbc.javax"> <include name="javax/**" /> </patternset> <patternset id="orgbc.lw-source" > <include name="org/bouncycastle/math/ec/*.java" /> <include name="org/bouncycastle/crypto/**" /> <include name="org/bouncycastle/util/**" /> <include name="org/bouncycastle/asn1/**" /> </patternset> <patternset id="orgbc.jce-source" > <include name="org/bouncycastle/jce/**" /> <exclude name="org/bouncycastle/jce/netscape/*" /> <exclude name="org/bouncycastle/jce/provider/X509CertificateObject.java" /> <exclude name="org/bouncycastle/jce/provider/RSAUtil.java" /> <exclude name="org/bouncycastle/jce/provider/JDKX509CertificateFactory.java" /> <exclude name="org/bouncycastle/jce/provider/test/RSATest.java" /> <exclude name="org/bouncycastle/jce/provider/test/RegressionTest.java" /> <!-- to make the friggin thing compile --> <exclude name="org/bouncycastle/jce/provider/test/DSATest.java" /> <exclude name="org/bouncycastle/jce/provider/test/DHTest.java" /> <exclude name="org/bouncycastle/jce/provider/test/Netscape*.java" /> <exclude name="org/bouncycastle/jce/provider/test/Named*.java" /> </patternset> <property name="build.compiler" value="classic" /> <property name="bcp" value="${env.JAVA_HOME}/lib/classes.zip" /> <path id="compile.cp"> <pathelement location="${master.classes}" /> <pathelement location="${bcp}" /> </path> <target name="local-compile" depends="llw-compile, ljce-compile" /> <!-- extra targets used in this file --> <target name="llw-compile" if="is.lw"> <echo message="jdk11.lw-compatibility" /> <javac srcdir="${master.home}/jdk1.1" destdir="${master.classes}" includeAntRuntime="no" includeJavaRuntime="no" debug="off" optimize="off" target="1.1"> <patternset refid="jdk11.lw-compatibility" /> <classpath refid = "compile.cp" /> </javac> <echo message="orgbc.lw-source" /> <javac srcdir="${master.src}" destdir="${master.classes}" includeAntRuntime="no" includeJavaRuntime="no" debug="off" optimize="off" target="1.1"> <patternset refid="orgbc.lw-source" /> <classpath refid = "compile.cp" /> </javac> </target> <target name="ljce-compile" if="is.jce" > <!-- cheat a bit here to remove duplication --> <antcall target="llw-compile"> <param name="is.lw" value="true" /> </antcall> <!-- now do the extra bits for the JCE --> <echo message="orgbc.jce-source" /> <javac srcdir="${master.src}" destdir="${master.classes}" includeAntRuntime="no" includeJavaRuntime="no" debug="off" optimize="off" target="1.1"> <patternset refid="orgbc.javax" /> <patternset refid="orgbc.jce-source" /> <classpath refid = "compile.cp" /> </javac> <echo message="jdk11.jce-compatibility" /> <javac srcdir="${master.home}/jdk1.1" destdir="${master.classes}" includeAntRuntime="no" includeJavaRuntime="no" debug="off" optimize="off" target="1.1"> <patternset refid="jdk11.jce-compatibility" /> <classpath refid = "compile.cp" /> </javac> </target> </project>
4)JSON(键值对)
JSON,全称是JavaScript Object Notation。它是基于JavaScript编程语言ECMA-262 3rd Edition-December 1999标准的一种轻量级的数据交换格式,主要用于用于跟服务器进行交换数据。跟XML相类似,它独立于语言,在跨平台数据传输上有很大的优势。
上面是百科的解释,可以说明json大概的意思和作用,json其实就是键值对存储数据。
举个例子:
var a ={"one":"一","two":"二","three":"三"},a就是一个json,a.one的值就是一,还可以内嵌数组
var b={"A":"[1,2,3,4,5,6,7]","B":"[a,b,c,d,e]"},b.A[0]的值就是1,json变量里面还可以内嵌json,可以内嵌数组,取值方法就是如上面的那种,数组用下标,json取键值对的名,使用起来很方便,数据存储格式简洁
5)自定义 如:struct结构体
举个例子:
struct Teacher { char name[32]; int age; char desc[1024] char *p //32 64 }
6)ASN.1抽象语法标记
ASN.1抽象语法标记(Abstract Syntax Notation One) ASN.1是一种 ISO/ITU-T 标准,描述了一种对数据进行表示、编码、传输和解码的数据格式。它提供了一整套正规的格式用于描述对象的结构,而不管语言上如何执行及这些数据的具体指代,也不用去管到底是什么样的应用程序。
ASN.1是描述在网络上传输信息格式的标准方法。它有两部分:一部分描述信息内数据,数据类型及序列格式;另一部分描述如何将各部分组成消息。它原来是作为X.409的一部分而开发的,后来才自己独立成为一个标准。ASN.1在OSI的ISO 8824/ITU X.208(说明语法)和ISO 8825/ITU X.209(说明基本编码规则)规范。
举个例子:
Report ::= SEQUENCE {
author OCTET STRING,
title OCTET STRING,
body OCTET STRING,
biblio Bibliography
}
在这个例子中,"Report"是由名字类型的信息组成的,而SEQUENCE表示消息是许多数据单元构成的,前三个数据单元的类型是OCTET STRING,而最后一个数据类型见下面的ASN.1语法表示它的意义:
Bibliography ::= SEQUENCE {
author OCTET STRING
title OCTET STRING
publisher OCTET STRING
year OCTET STRING
}
ASN.1中定义的数据类型既有简单的基本数据类型,也有复杂的结构类型。
(1)基本类型是不可再再分的,包括:
o 布尔型(BOOLEAN)
o 整型(INTEGER)
o 实型(REAL)
o 位串类型(BITSTRING)
o 8位位组类型(OCTET STRING)
o 枚举类型(ENUMERATED)
o 空类型(NULL)
o 对象标识符(OBJECT IDENTIFIER)
(2)除基本类型,ASN.1还定义了多种复杂的结构类型,例如:
o SEQUENCE:有序的数据集合(序列),由不同类型的数据组成。SEQUENCE结构强调内部成员的排序
o SEQUENCE OF:有序的数据集合,类似于C语言的数组,由同一类型的数据组成。
o SET:由不同类型的数据组成的集合,用来描述复杂的信息对象,对内部成员的顺序不作要求,类似于C语言的结构体类型
o CHOICE:选择结构,在列出的内部成员中,只能选择其中之一,类似于C语言中的共用体类型
2、BER报文编解码
》结构体编码原理图:
3、指针充当函数返回值
》二级指针作为函数参数,可以充当函数返回值。
测试:demo.c
#define _CRT_SECURE_NO_WARNINGS #include "stdio.h" #include "stdlib.h" #include "string.h" typedef struct _Teacher { char name[64]; int age; char *p; int plen; }Teacher; // 传入、传出、传入传出。 int TeacherEncode(Teacher *pThecher, unsigned char **out, int *outlen) { unsigned char *tmp = malloc(32); strcpy(tmp, "xxxxxyyyyy"); *out = tmp; *outlen = strlen(tmp); return 0; } int TeacherDecode(unsigned char *indata, int inLen, Teacher **pStruct) { return 0; } int main(void) { int ret = 0; Teacher t1; unsigned char *myOut = NULL; int myOutlen = 0; t1.age = 10; strcpy(t1.name, "myName"); t1.p = malloc(64); strcpy(t1.p, "aaaabbbb"); t1.plen = strlen(t1.p); printf("before -- myout = %s, myOutlen = %d\n", myOut, myOutlen); TeacherEncode(&t1, &myOut, &myOutlen); printf("after -- myout = %s, myOutlen = %d\n", myOut, myOutlen); printf("hello...\n"); system("pause"); return 0; }
4、统一报文编解码函数接口
学会调用itcast_asn1_der.h和itcast_asn1_der.c
教师结构体编码:
》整型:
DER_ItAsn1_WriteInteger(ITCAST_UINT32 integer, ITASN1_INTEGER **ppDerInteger);
》字符串类型:
1. DER_ITCAST_String_To_AnyBuf(ITCAST_ANYBUF **pOriginBuf, unsigned char * strOrigin,int strOriginLen);
2. DER_ItAsn1_WritePrintableString(ITASN1_PRINTABLESTRING *pPrintString, ITASN1_PRINTABLESTRING **ppDerPrintString);
int EncodeChar(char *pData, int dataLen, ITCAST_ANYBUF **outBuf); 合并 1. 2.
》结构体类型:
DER_ItAsn1_WriteSequence(ITASN1_SEQUENCE *pSequence, ITCAST_ANYBUF **ppDerSequence);
5、教师结构体编码实现
》编写demo01.c
注意:导入头文件:itcast_asn1_der.h和itcastderlog.h
》测试与查看der文件
因为BLV格式的文件无法查看,无法分析解码,所以提供写入ber文件的方式,使用-der查看工具.exe进行查看(直接把生成的teacher.ber拖入即可)
int mywritefile(unsigned char *buf, int len) { FILE *fp = NULL; fp = fopen("c:/itcast/teacher.ber", "wb+"); if (fp == NULL) { printf("fopen file error \n"); return -1; } fwrite(buf, 1, len, fp); fclose(fp); return 0; }
demo01.c
#define _CRT_SECURE_NO_WARNINGS #include "stdio.h" #include "stdlib.h" #include "string.h" #include "itcast_asn1_der.h" #include "itcastderlog.h" typedef struct _Teacher { char name[64]; int age; char *p; int plen; }Teacher; // 传入、传出、传入传出。 int TeacherEncode(Teacher *pThecher, unsigned char **out, int *outlen) { int ret = 0; ITCAST_ANYBUF *pTmp = NULL, *pHeadBuf = NULL; ITCAST_ANYBUF *pTmpBuf = NULL; ITCAST_ANYBUF *pOutData = NULL; unsigned char *tmpout = NULL; int tmpoutlen = 0; //将 char * 类型的name 转换成 ITCAST_ANYBUF 类型 ret = DER_ITCAST_String_To_AnyBuf(&pTmpBuf, pThecher->name, strlen(pThecher->name)); if (ret != 0) { printf("DER_ITCAST_String_To_AnyBuf error: %d\n", ret); return ret; } // 编码 name --> TLV ret = DER_ItAsn1_WritePrintableString(pTmpBuf, &pHeadBuf); if (ret != 0) { printf("DER_ItAsn1_WritePrintableString error: %d\n", ret); return ret; } pTmp = pHeadBuf; // 编码 age ret = DER_ItAsn1_WriteInteger(pThecher->age, &(pTmp->next)); if (ret != 0) { printf("DER_ItAsn1_WriteInteger error: %d\n", ret); return ret; } pTmp = pTmp->next; //编码 p char * ret = EncodeChar(pThecher->p, pThecher->plen, &pTmp->next); if (ret != 0) { printf("EncodeChar error: %d\n", ret); return ret; } pTmp = pTmp->next; //编码 plen ret = DER_ItAsn1_WriteInteger(pThecher->plen, &(pTmp->next)); if (ret != 0) { printf("DER_ItAsn1_WriteInteger plen error: %d\n", ret); return ret; } //编码大结构体 ret = DER_ItAsn1_WriteSequence(pHeadBuf, &pOutData); if (ret != 0) { printf("DER_ItAsn1_WriteSequence error: %d\n", ret); return ret; } *out = pOutData->pData; *outlen = pOutData->dataLen; return 0; } int mywritefile(unsigned char *buf, int len) { FILE *fp = NULL; fp = fopen("c:/itcast/teacher.ber", "wb+"); if (fp == NULL) { printf("fopen file error \n"); return -1; } fwrite(buf, 1, len, fp); fclose(fp); return 0; } int main(void) { int ret = 0; Teacher t1; unsigned char *myOut = NULL; int myOutlen = 0; t1.age = 10; strcpy(t1.name, "myName"); t1.p = malloc(64); strcpy(t1.p, "aaaabbbb"); t1.plen = strlen(t1.p); TeacherEncode(&t1, &myOut, &myOutlen); mywritefile(myOut, myOutlen); printf("hello...\n"); system("pause"); return 0; }
6、解码教师结构体分析
7、教师结构体解码实现
demo01.c
#define _CRT_SECURE_NO_WARNINGS #include "stdio.h" #include "stdlib.h" #include "string.h" #include "itcast_asn1_der.h" #include "itcastderlog.h" typedef struct _Teacher { char name[64]; int age; char *p; int plen; }Teacher; void freeTeacher(Teacher **pTeacher) { if (pTeacher == NULL) { return; } if (pTeacher != NULL) { if ((*pTeacher)->p != NULL) { free((*pTeacher)->p); (*pTeacher)->p = NULL; } free(*pTeacher); *pTeacher = NULL; } } // 传入、传出、传入传出。 int TeacherEncode(Teacher *pThecher, unsigned char **out, int *outlen) { int ret = 0; ITCAST_ANYBUF *pTmp = NULL, *pHeadBuf = NULL; ITCAST_ANYBUF *pTmpBuf = NULL; ITCAST_ANYBUF *pOutData = NULL; unsigned char *tmpout = NULL; int tmpoutlen = 0; //将 char * 类型的name 转换成 ITCAST_ANYBUF 类型 ret = DER_ITCAST_String_To_AnyBuf(&pTmpBuf, pThecher->name, strlen(pThecher->name)); if (ret != 0) { printf("DER_ITCAST_String_To_AnyBuf error: %d\n", ret); return ret; } // 编码 name --> TLV ret = DER_ItAsn1_WritePrintableString(pTmpBuf, &pHeadBuf); if (ret != 0) { DER_ITCAST_FreeQueue(pTmpBuf); printf("DER_ItAsn1_WritePrintableString error: %d\n", ret); return ret; } DER_ITCAST_FreeQueue(pTmpBuf); pTmp = pHeadBuf; // 编码 age ret = DER_ItAsn1_WriteInteger(pThecher->age, &(pTmp->next)); if (ret != 0) { printf("DER_ItAsn1_WriteInteger error: %d\n", ret); return ret; } pTmp = pTmp->next; //编码 p char * ret = EncodeChar(pThecher->p, pThecher->plen, &pTmp->next); if (ret != 0) { printf("EncodeChar error: %d\n", ret); return ret; } pTmp = pTmp->next; //编码 plen ret = DER_ItAsn1_WriteInteger(pThecher->plen, &(pTmp->next)); if (ret != 0) { printf("DER_ItAsn1_WriteInteger plen error: %d\n", ret); return ret; } //编码大结构体 ret = DER_ItAsn1_WriteSequence(pHeadBuf, &pOutData); if (ret != 0) { DER_ITCAST_FreeQueue(pHeadBuf); printf("DER_ItAsn1_WriteSequence error: %d\n", ret); return ret; } *out = pOutData->pData; *outlen = pOutData->dataLen; return 0; } int mywritefile(unsigned char *buf, int len) { FILE *fp = NULL; fp = fopen("c:/itcast/teacher.ber", "wb+"); if (fp == NULL) { printf("fopen file error \n"); return -1; } fwrite(buf, 1, len, fp); fclose(fp); return 0; } int TeacherDecode(unsigned char *indata, int inLen, Teacher **pStruct) { int ret = 0; ITCAST_ANYBUF *pTmp = NULL, *pHead = NULL; ITCAST_ANYBUF *pOutData = NULL; ITCAST_ANYBUF *tmpAnyBuf = NULL; Teacher *pStrTeacher = NULL; // 转码 BER 报文 unsigned char * --> ITCAST_ANYBUF ret = DER_ITCAST_String_To_AnyBuf(&tmpAnyBuf, indata, inLen); if (ret != 0) { if (tmpAnyBuf != NULL) DER_ITCAST_FreeQueue(tmpAnyBuf); printf(" Decode DER_ITCAST_String_To_AnyBuf error: %d\n", ret); return ret; } // 解码大Teacher 结构体 ret = DER_ItAsn1_ReadSequence(tmpAnyBuf, &pHead); if (ret != 0) { if (tmpAnyBuf != NULL) DER_ITCAST_FreeQueue(tmpAnyBuf); printf(" Decode DER_ItAsn1_ReadSequence error: %d\n", ret); return ret; } // 给Teacher 结构体 malloc 空间。 if (pStrTeacher == NULL) { pStrTeacher = (Teacher *)malloc(sizeof(Teacher)); if (pStrTeacher == NULL) { DER_ITCAST_FreeQueue(pHead); ret = -1; printf("Teacher malloc error: %d\n", ret); return ret; } memset(pStrTeacher, 0, sizeof(Teacher)); } pTmp = pHead; // 解码 name ret = DER_ItAsn1_ReadPrintableString(pTmp, &pOutData); if (ret != 0) { DER_ITCAST_FreeQueue(pHead); freeTeacher(&pStrTeacher); printf(" Decode DER_ItAsn1_ReadPrintableString name error: %d\n", ret); return ret; } // ppPrintString -> pData; ---> name memcpy(pStrTeacher->name, pOutData->pData, pOutData->dataLen); pTmp = pTmp->next; // 解码age ret = DER_ItAsn1_ReadInteger(pTmp, &pStrTeacher->age); if (ret != 0) { DER_ITCAST_FreeQueue(pHead); freeTeacher(&pStrTeacher); printf(" Decode DER_ItAsn1_ReadInteger age error: %d\n", ret); return ret; } pTmp = pTmp->next; // 解码 p ret = DER_ItAsn1_ReadPrintableString(pTmp, &pOutData); if (ret != 0) { DER_ITCAST_FreeQueue(pHead); freeTeacher(&pStrTeacher); printf(" Decode DER_ItAsn1_ReadPrintableString p error: %d\n", ret); return ret; } // 给Teacher 结构体中的 p 指针开辟空间 pStrTeacher->p = malloc(pOutData->dataLen + 1); if (pStrTeacher->p == NULL) { DER_ITCAST_FreeQueue(pHead); freeTeacher(&pStrTeacher); ret = -2; printf("Teacher->p malloc error: %d\n", ret); return ret; } memcpy(pStrTeacher->p, pOutData->pData, pOutData->dataLen); //pStrTeacher->p[pOutData->dataLen - 4] = 'R';//测试调试 pStrTeacher->p[pOutData->dataLen] = '\0'; pTmp = pTmp->next; // 解码plen ret = DER_ItAsn1_ReadInteger(pTmp, &pStrTeacher->plen); if (ret != 0) { DER_ITCAST_FreeQueue(pHead); freeTeacher(&pStrTeacher); printf(" Decode DER_ItAsn1_ReadInteger plen error: %d\n", ret); return ret; } *pStruct = pStrTeacher; return 0; } int main(void) { int ret = 0; Teacher t1; Teacher *pt2 = NULL; unsigned char *myOut = NULL; int myOutlen = 0; t1.age = 10; strcpy(t1.name, "myName"); t1.p = malloc(64); strcpy(t1.p, "aaaabbbb"); t1.plen = strlen(t1.p); TeacherEncode(&t1, &myOut, &myOutlen); mywritefile(myOut, myOutlen); TeacherDecode(myOut, myOutlen, &pt2); if (strcmp(t1.name, pt2->name) == 0 && memcmp(t1.p, pt2->p, pt2->plen) == 0) { printf("编码 == 解码 \n"); } else { printf("编码 != 解码 \n"); } freeTeacher(&pt2); printf("hello...\n"); system("pause"); return 0; }
8、内存释放
free
》小技巧:先把项目整体逻辑梳理完毕,然后再往里边添加释放内存的模块。
把握的原则:后期不在使用的,释放掉。
》释放Teacher结构体
void freeTeacher(Teacher **pTeacher) { if (pTeacher == NULL) { return; } if (pTeacher != NULL) { if ((*pTeacher)->p != NULL) { free((*pTeacher)->p); (*pTeacher)->p = NULL; } free(*pTeacher); *pTeacher = NULL; } }
注意:此处的参数最好是二级指针,释放完空间后可以赋值为空指针。如果是一级指针,赋值后地址的内容将不能改变。
9、统一报文编解码函数接口
》项目架构图:
》函数接口封装
》问题1:当用户调用的时候,如果有多种结构体类型(teacher、student、nurse...),需要看调用那个结构体,调用哪种编解码函数,如何采取给用户一套接口,不管什么结构体,用户都只调用一套接口编码、解码、释放内存呢?方便用户?
》问题2:若100个结构体,如何对报文进行统一报文编码解码;实现业务流和基础组件的解耦合
分析:提供一套,然后里面提供类型type
int MsgEncode(void *teacher, unsigned char **out, int *outlen, int type);
int MsgDecode(unsigned char *out, int outlen, void ** teacher, int *type);
int MsgFree(void **teacher, int type);
》重点:报文编码解码组件和业务流模块的解耦合
统一报文编码解码设计思想:
统一报文编解码组件:实现了把各种各样的数据类型进行隐藏、把各种各样的报文结果类型进行隐藏。
第一步:定义统一报文API 打桩API函数 (keymng_msg.c keymng_msg.h)
》keymng_msg.h
#ifndef _KEYMNG_MSG_H_ #define _KEYMNG_MSG_H_ #ifdef __cplusplus extern "C" { #endif #define KeyMng_ParamErr 200 //输入参数失败 #define KeyMng_TypeErr 201 //输入类型失败 #define KeyMng_MallocErr 202 //分配内存失败 #define KeyMng_NEWorUPDATE 1 //1 密钥更新 #define KeyMng_Check 2 //2 密钥校验 #define KeyMng_Revoke 3 //3 密钥注销 ; #define ID_MsgKey_Req 60 //密钥请求报文 typedef struct _MsgKey_Req { //1 密钥更新 //2 密钥校验; //3 密钥注销 int cmdType; //报文命令码 char clientId[12]; //客户端编号 char AuthCode[16]; //认证码 char serverId[12]; //服务器端I编号 char r1[64]; //客户端随机数 }MsgKey_Req; //密钥应答报文 #define ID_MsgKey_Res 61 typedef struct _MsgKey_Res { int rv; //返回值 char clientId[12]; //客户端编号 char serverId[12]; //服务器编号 unsigned char r2[64]; //服务器端随机数 }MsgKey_Res; /* pstruct : 输入的报文数据 ; (指向相应结构体的指针) type : 输入的类型标识(函数内部通过type 得到 pstruct 所指向的报文类型) poutData: 输出的编码后的报文 ; outlen : 输出的数据长度; */ int MsgEncode( void *pStruct , /*in*/ int type, unsigned char **outData, /*out*/ int *outLen ); /* inData : 输入的编码后的数据; inLen : 输入的数据长度 ; pstruct : 输出的解码后的数据; (其空间是在内部开辟的,也需要用内部定义的free函数进行释放) type : 结构的类型标识(返回类型标识,使得调用者通过flag进行判断,将pstruct 转换为相应的结构) */ int MsgDecode( unsigned char *inData,/*in*/ int inLen, void **pStruct /*out*/, int *type /*out*/); /* 释放 MsgEncode( )函数中的outData; 方法:MsgMemFree((void **)outData, 0); 释放MsgDecode( )函数中的pstruct结构体,MsgMemFree((void **)outData, type); type : 输入参数,便于函数判断调用哪个结构体的free函数 */ int MsgMemFree(void **point,int type); #ifdef __cplusplus } #endif #endif
10、报文接口封装注意事项
1)对于type的处理?仍需要再次封装。
2)在 MsgEncode中提供判断type,采用switch..case..,采用宏的形式在case后判断。
int MsgEncode( void *pStruct , /*in*/ int type, unsigned char **outData, /*out*/ int *outLen ) { //编码type switch(type) case 80: TeacherEncode(); case 60: 密钥请求Encode(); case 61: 密钥应答Encode(); }
3)TeacherEncode无法直接调用?改为输出AnyBuf类型,然后用大结构体封装。
在学习安全传输平台项目总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
posted on 2020-07-24 20:19 Alliswell_WP 阅读(869) 评论(0) 编辑 收藏 举报