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


    在学习安全传输平台项目总结了笔记,并分享出来。有问题请及时联系博主: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
    ", myOut, myOutlen);
        
        TeacherEncode(&t1, &myOut, &myOutlen);
    
        printf("after -- myout = %s, myOutlen = %d
    ", myOut, myOutlen);
    
    
        printf("hello...
    ");
        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 
    ");
    		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
    ", ret);
            return ret;
        }
    
        // 编码 name  --> TLV
        ret = DER_ItAsn1_WritePrintableString(pTmpBuf, &pHeadBuf);
        if (ret != 0) {
            printf("DER_ItAsn1_WritePrintableString error: %d
    ", ret);
            return ret;
        }
        pTmp = pHeadBuf;
    
        // 编码 age
        ret = DER_ItAsn1_WriteInteger(pThecher->age, &(pTmp->next));
        if (ret != 0) {
            printf("DER_ItAsn1_WriteInteger error: %d
    ", ret);
            return ret;
        }
        pTmp = pTmp->next;
    
        //编码 p  char *
        ret = EncodeChar(pThecher->p, pThecher->plen, &pTmp->next);
        if (ret != 0) {
            printf("EncodeChar error: %d
    ", 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
    ", ret);
            return ret;
        }
    
        //编码大结构体
        ret = DER_ItAsn1_WriteSequence(pHeadBuf, &pOutData);
        if (ret != 0) {
            printf("DER_ItAsn1_WriteSequence error: %d
    ", 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 
    ");
            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...
    ");
        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
    ", ret);
            return ret;
        }
    
        // 编码 name  --> TLV
        ret = DER_ItAsn1_WritePrintableString(pTmpBuf, &pHeadBuf);
        if (ret != 0) {
            DER_ITCAST_FreeQueue(pTmpBuf);
            printf("DER_ItAsn1_WritePrintableString error: %d
    ", 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
    ", ret);
            return ret;
        }
        pTmp = pTmp->next;
    
        //编码 p  char *
        ret = EncodeChar(pThecher->p, pThecher->plen, &pTmp->next);
        if (ret != 0) {
            printf("EncodeChar error: %d
    ", 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
    ", ret);
            return ret;
        }
    
        //编码大结构体
        ret = DER_ItAsn1_WriteSequence(pHeadBuf, &pOutData);
        if (ret != 0) {
            DER_ITCAST_FreeQueue(pHeadBuf);
            printf("DER_ItAsn1_WriteSequence error: %d
    ", 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 
    ");
            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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", 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
    ", ret);
            return ret;
        }
        memcpy(pStrTeacher->p, pOutData->pData, pOutData->dataLen);
        //pStrTeacher->p[pOutData->dataLen - 4] = 'R';//测试调试
        pStrTeacher->p[pOutData->dataLen] = '';
    
        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
    ", 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("编码 == 解码 
    ");
        }
        else
        {
            printf("编码 != 解码 
    ");
        }
    
        freeTeacher(&pt2);
    
        printf("hello...
    ");
        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,转载请注明出处。

  • 相关阅读:
    【C语言】学习笔记5——指针(1)
    【C语言】学习笔记4——数组
    【leetcode】Contest98
    【Python】从0开始写爬虫——豆瓣电影
    C# WPF 文件复制,相对路径
    WPF DataGrid多表头/列头,多行头,合并单元格,一列占据多行
    WPF Image Source 设置相对路径图片
    WPF Blend 一个动画结束后另一个动画开始执行(一个一个执行)
    WPF 操作XML 读写
    WPF 选择电脑文件显示路径,弹出资源管理器,打开文件
  • 原文地址:https://www.cnblogs.com/Alliswell-WP/p/CPlusPlus_SecureTransmissionPlatform_Project02.html
Copyright © 2020-2023  润新知