安全传输平台项目——统一报文编解码一教师结构体编码

在学习安全传输平台项目总结了笔记,并分享出来。有问题请及时联系博主: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
­消息体的内容(略)
Request和Response的格式

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>
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>
xml

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;
}
demo.c

 

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;
}
demo01.c

 

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;
}
demo01.c

 

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  阅读(818)  评论(0编辑  收藏  举报

导航