这几天开始做项目了,涉及到项目传输时的报文设计,在C/S架构的项目设计中,传递数据一定要有一定的格式,这样服务端和客户端才能区分开来。除了格式以外还要考虑到传递的数据如果是指针怎么办?如果是NULL怎么办?等等问题,这些问题其实有很多中解决方案,本文就介绍一种 ASN.1 编码格式,当然本文没办法大篇幅的介绍 ASN.1 编码的格式、好处等等内容,网络上的资料有很多,本文主要是记录代码上如何实现对基础数据类型的编码,以备以后忘记了具体细节时回来查看。
相关头文件下载
点击下载:itcast_asn1_der 包含.h和.cpp
代码实现
代码语言:javascript复制#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include “itcast_asn1_der.h”
typedef struct _tag_teacher
{
int age;
char name[20];
char* p;
char plen;
}Teacher;
int mywritefile(unsigned char *buf, int len)
{
FILE *fp = NULL;
#ifdef WIN32
fopen_s(&fp, “c:/teacher.ber”, “wb ”);
#else
fp = fopen(“c:/teacher.ber”, “wb ”);
#endif
if (fp == NULL)
{
printf(“fopen file error n”);
return -1;
}
fwrite(buf, 1, len, fp);
fclose(fp);
return 0;
}
/*
函数功能:编码 Teacher 结构体,通过
参数介绍:
Teacher *pStruct:Teacher 类型的结构体指针
unsigned char** out:unsigned char 类型的空指针,用来接收内部处理完成后返回的数据
int* outlen:int 类型的指针,用来接收内部处理完成后数据的长度
*/
int EncodeStruct(Teacher *pStruct, unsigned char** out, int* outlen)
{
int ret = 0;// 记录返回值
ITCAST_ANYBUF *pHeadBuf = NULL;// 头节点
ITCAST_ANYBUF *pCur = NULL;// 游标,储存新编码的节点域并与头节点连接
ITCAST_ANYBUF *pTeacher = NULL;// 临时节点用来接收整条链表编码后的结果
if (out == NULL outlen == NULL)
{
return -1;
}
// 如果传递的第一个参数是NULL,那么正常也对 NULL 进行编码
if (pStruct == NULL)
{
DER_ItAsn1_WriteNull(&pTeacher);
goto END;
}
// 编码第一个 int 域保存到第一个节点 pHeadBuf 中
ret = DER_ItAsn1_WriteInteger(pStruct->age, &pHeadBuf);
if (ret != 0)
{
printf(“func DER_ItAsn1_WriteInteger() err:%dn”, ret);
return ret;
}
// 让游标指向头节点
pCur = pHeadBuf;
// 让头节点的下一个节点(pCur->next)接收编码name的数据
ret = EncodeChar(pStruct->name, strlen(pStruct->name), &pCur->next);
if (ret != 0)
{
DER_ITCAST_FreeQueue(pHeadBuf);
printf(“func EncodeChar() err:%dn”, ret);
return ret;
}
// 连接链表,向前递进,编码指针域
pCur = pCur->next;
ret = EncodeChar(pStruct->p, pStruct->plen, &pCur->next);
if (ret != 0)
{
DER_ITCAST_FreeQueue(pHeadBuf);
printf(“func EncodeChar() err:%dn”, ret);
return ret;
}
// 连接链表,向前递进,编码 plen
pCur = pCur->next;
ret = DER_ItAsn1_WriteInteger(pStruct->plen, &pCur->next);
if (ret != 0)
{
DER_ITCAST_FreeQueue(pHeadBuf);
printf(“func DER_ItAsn1_WriteInteger() err:%dn”, ret);
return ret;
}
// 将整个链表一起编码
ret = DER_ItAsn1_WriteSequence(pHeadBuf, &pTeacher);
if (ret != 0)
{
DER_ITCAST_FreeQueue(pHeadBuf);
printf(“func DER_ItAsn1_WriteSequence() err:%dn”, ret);
return ret;
}
END:
// 将数据传出
*out = ( unsigned char* ) malloc( pTeacher->dataLen );
#ifdef WIN32
memcpy_s(*out, pTeacher->dataLen, pTeacher->pData, pTeacher->dataLen);
#else
memcpy(*out, pTeacher->pData, pTeacher->dataLen);
#endif // WIN32
*outlen = pTeacher->dataLen;
// 释放内存
DER_ITCAST_FreeQueue(pHeadBuf);
DER_ITCAST_FreeQueue(pTeacher);
return ret;
}
int TeacherDecode(unsigned char* out, int outlen, Teacher** pTeacher)
{
int ret = 0;
return ret;
}
int main(int argc, char* argv[])
{
int ret = 0;
Teacher teacher;
teacher.age = 25;
#ifdef WIN32
strcpy_s(teacher.name, sizeof(teacher.name), “myCode”);
#else
strcpy(teacher.name, “myCode”);
#endif // WIN32
teacher.p = (char*)malloc(100);
#ifdef WIN32
strcpy_s(teacher.p, 100, “pStructTest”);
#else
strcpy(teacher.p, “pStructTest”);
#endif // WIN32
teacher.plen = strlen(teacher.p);
// 接收数据的变量
unsigned char*out = NULL;
intoutlen = 0;
// 编码结构体
ret = EncodeStruct(&teacher, &out, &outlen);
if (ret != 0)
{
free(teacher.p);
printf(“func EncodeStruct() err:%dn”, ret);
return ret;
}
// 将编码后的数据写入到文件中,可通过 ber 查看工具进行查看
mywritefile(out, outlen);
// 解码
Teacher *pTeacher = NULL;
ret = TeacherDecode(out, outlen, &pTeacher);
if (teacher.age == pTeacher->age &&
strcmp(teacher.name, pTeacher->name) &&
strcmp(teacher.p, pTeacher->p) &&
teacher.plen == pTeacher->plen)
{
printf(“一样n”);
}
else
{
printf(“不一样n”);
}
// 释放内存
free(out);
free(teacher.p);
return 0;
}
代码编译
在 VS 中新建一个 win32 控制台空项目,新建 mian.c 文件将代码粘贴进去,然后在项目中右键导入现有项,将上面下载后得到的几个文件包含到项目目录中即可编译,根据自己的需要把注释的部分解除注释查看效果。