首页 > 技术文章 > 深入理解C语言-接口封装设计思想

cj5785 2019-04-02 23:28 原文

断层思维

在设计时候,不需要知道实现,只需要知道如何使用

接口设计的设计思路

Sckclient客户端api模型
第一套API
(*.h)

#ifndef _SCK_CLINT_H_
#define _SCK_CLINT_H_

#ifdef  __cplusplus
extern "C" {
#endif

//函数声明
// 1、客户端环境初始化
int sckClient_init(void **handle); 
// 2、客户端发送报文
int sckClient_send(void *handle, unsigned char *data, int datalen);
// 3、客户端端接受报文
int sckClient_rev(void *handle, unsigned char *out, int *outlen); 
// 4、客户端环境释放 
int sckClient_destroy(void *handle);

#ifdef  __cplusplus
}
#endif
#endif

(*.c)

#include "stdlib.h"
#include "stdio.h"
#include "string.h"

typedef struct _SCK_HANDLE {
	char           version[16];
	char           serverip[16];
	int            serverport;
	unsigned char *buf ;
	int            buflen;
}SCK_HANDLE;

//客户端初始化 获取handle上下
__declspec(dllexport) 
int cltSocketInit(void **handle /*out*/)
{
	int ret = 0;
	SCK_HANDLE *sh = NULL;
	sh = (SCK_HANDLE *)malloc(sizeof(SCK_HANDLE));
	if (sh == NULL)
	{
		ret = -1;
		printf("func cltSocketInit() err: %d, malloc err....", ret);
		return ret;
	}
	memset(sh, 0, sizeof(SCK_HANDLE));
	strcpy(sh->serverip, "192.168.0.128");
	sh->serverport= 88;

	*handle = sh;
	return ret;
}

//客户端发报文
__declspec(dllexport) 
int cltSocketSend(void *handle /*in*/, unsigned char *buf /*in*/,  int buflen /*in*/)
{
	int		ret = 0;
	SCK_HANDLE *sh = NULL; 
	
	if (handle==NULL || buf==NULL)
	{
		ret = -1;
		printf("func cltSocketSend() err: %d, (handle==NULL || buf==NULL)", ret);
		return ret;
	}
	sh = (SCK_HANDLE *)handle ;
	sh->buf = (char *)malloc(buflen);
	if (sh->buf == NULL)
	{
		ret = -2;
		printf("func cltSocketSend() err: %d, (buflen:%d)", ret, buflen);
		return ret;
	}
	memcpy(sh->buf, buf, buflen);
	sh->buflen = buflen;

	return ret;
}


//客户端收报文
__declspec(dllexport) 
int cltSocketRev(void *handle /*in*/, unsigned char *buf /*in*/, int *buflen /*in out*/)
{
	int  ret = 0;
	SCK_HANDLE *sh = NULL; 

	if (handle==NULL || buf==NULL || buflen==NULL)
	{
		ret = -1;
		printf("func cltSocketSend() err: %d, ((handle==NULL || buf==NULL || buflen==NULL))", ret);
		return ret;
	}

	sh = (SCK_HANDLE *)handle;

	memcpy(buf, sh->buf, sh->buflen);
	*buflen  = sh->buflen;

	if (sh->buf != NULL)
	{
		free(sh->buf);
		sh->buf = NULL; //把状态回到原始
		sh->buflen = 0;
	}
	return ret;
}


//客户端释放资源
__declspec(dllexport) 
int cltSocketDestory(void *handle/*in*/)
{
	int  ret = 0;
	SCK_HANDLE *sh = NULL; 

	if (handle==NULL )
	{
		ret = -1;
		printf("func cltSocketSend() err: %d, ((handle==NULL )", ret);
		return ret;
	}

	sh = (SCK_HANDLE *)handle;
	
	if (sh->buf != NULL)
	{
		free(sh->buf);
		sh->buf = NULL;
		sh->buflen = 0;
	}
	free(sh);

	return ret;
}

第二套API
(*.h)

#ifndef _SCK_CLINT02_H_
#define _SCK_CLINT02_H_

#ifdef  __cplusplus
extern "C" {
#endif

//函数声明
// 1、客户端环境初始化
int sckClient_init2(void **handle); 
// 2、客户端发送报文
int sckClient_send2(void *handle, unsigned char *data, int datalen);
// 3、客户端端接受报文
int sckClient_rev2(void *handle, unsigned char **out, int *outlen); 
int sckClient_rev2_Free(void **p); 
// 4、客户端环境释放 
int sckClient_destroy2(void **handle);

#ifdef  __cplusplus
}
#endif

#endif

(*.c)

#include "stdlib.h"
#include "stdio.h"
#include "string.h"


typedef struct _SCK_HANDLE {
	char           version[16];
	char           serverip[16];
	int            serverport;
	unsigned char *buf ;
	int            buflen;
}SCK_HANDLE;

//客户端环境初始化
__declspec(dllexport)
int cltSocketInit2(void **handle)
{
	return cltSocketInit(handle /*out*/);
}

//客户端发报文
__declspec(dllexport)
int cltSocketSend2(void *handle, unsigned char *buf,  int buflen)
{
	return cltSocketSend(handle /*in*/, buf /*in*/, buflen /*in*/);
}
//客户端收报文
__declspec(dllexport)
int cltSocketRev2(void *handle, unsigned char **buf, int *buflen)
{
	int  ret = 0;
	SCK_HANDLE *sh = NULL; 

	if (handle==NULL || buf==NULL || buflen==NULL)
	{
		ret = -1;
		ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret, "func cltSocketRev2() err: %d,  (handle==NULL || buf==NULL || buflen==NULL)", ret);
		return ret;
	}

	sh = (SCK_HANDLE *)handle;

	*buf = (char *)malloc( sh->buflen);

	memcpy(*buf, sh->buf, sh->buflen);
	*buflen  = sh->buflen;
	return ret;
}

__declspec(dllexport)
int cltSocketRev2_Free(unsigned char **buf)
{
	if (buf == NULL)
	{
		return -1;
	}
	free(*buf);
	*buf = NULL;
	return 0;
}
//客户端释放资源
__declspec(dllexport)
int cltSocketDestory2(void **handle)
{
	int  ret = 0;
	SCK_HANDLE *sh = NULL; 
	

	if (handle==NULL )
	{
		ret = -1;
		ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret, "func cltSocketSend() err: %d, ((handle==NULL )", ret);
		return ret;
	}

	sh = (SCK_HANDLE *)*handle;

	if (sh->buf != NULL)
	{
		free(sh->buf);
		sh->buf = NULL;
		sh->buflen = 0;
	}
	free(sh);
	*handle = NULL; //把实参赋值null

	return ret;
}

日志打印

(*.h)

#ifndef __LOG_H_
#define __LOG_H_
/***********************************************************************
const char *file:文件名称
int line:文件行号
int level:错误级别
0 -- 没有日志
1 -- debug级别
2 -- info级别
3 -- warning级别
4 -- err级别
int status:错误码
const char *fmt:可变参数
***********************************************************************/
//实际使用的Level
extern int  LogLevel[5];
void LOG(const char *file, int line, int level, int status, const char *fmt, ...);
#endif

(*.c)

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "Log.h"

#define DEBUG_FILE_	"error.log"
#define MAX_STRING_LEN 		10240
//日志输出目录
#define FILE_SPACE "c:/log/%s"

//Level类别
#define NO_LOG_LEVEL	0
#define DEBUG_LEVEL		1
#define INFO_LEVEL		2
#define WARNING_LEVEL	3
#define ERROR_LEVEL		4

//日志等级
int  LogLevel[5] = { NO_LOG_LEVEL, DEBUG_LEVEL, INFO_LEVEL, WARNING_LEVEL, ERROR_LEVEL };

//Level的名称
char LevelName[5][10] = { "NOLOG", "DEBUG", "INFO", "WARNING", "ERROR" };

static int Error_GetCurTime(char* strTime)
{
	struct tm*		tmTime = NULL;
	size_t			timeLen = 0;
	time_t			tTime = 0;

	tTime = time(NULL);
	tmTime = localtime(&tTime);
	//timeLen = strftime(strTime, 33, "%Y(Y)%m(M)%d(D)%H(H)%M(M)%S(S)", tmTime);
	timeLen = strftime(strTime, 33, "%Y.%m.%d %H:%M:%S", tmTime);

	return timeLen;
}

static int Error_OpenFile(int* pf)
{
	char	fileName[1024];

	memset(fileName, 0, sizeof(fileName));
#ifdef WIN32
	sprintf(fileName, FILE_SPACE, DEBUG_FILE_);
#else
	sprintf(fileName, FILE_SPACE, DEBUG_FILE_);
	//sprintf(fileName, "%s/log/%s", getenv("HOME"), DEBUG_FILE_);
#endif

	*pf = open(fileName, O_WRONLY | O_CREAT | O_APPEND, 0666);
	if (*pf < 0)
	{
		return -1;
	}

	return 0;
}

static void Error_Core(const char *file, int line, int level, int status, const char *fmt, va_list args)
{
	char str[MAX_STRING_LEN];
	int	 strLen = 0;
	char tmpStr[64];
	int	 tmpStrLen = 0;
	int  pf = 0;

	//初始化
	memset(str, 0, MAX_STRING_LEN);
	memset(tmpStr, 0, 64);

	//加入LOG时间
	tmpStrLen = Error_GetCurTime(tmpStr);
	tmpStrLen = sprintf(str, "[%s] ", tmpStr);
	strLen = tmpStrLen;

	//加入LOG等级
	tmpStrLen = sprintf(str + strLen, "[%s] ", LevelName[level]);
	strLen += tmpStrLen;

	//加入LOG状态
	if (status != 0)
	{
		tmpStrLen = sprintf(str + strLen, "[ERRNO is %d] ", status);
	}
	else
	{
		tmpStrLen = sprintf(str + strLen, "[SUCCESS] ");
	}
	strLen += tmpStrLen;

	//加入LOG信息
	tmpStrLen = vsprintf(str + strLen, fmt, args);
	strLen += tmpStrLen;

	//加入LOG发生文件
	tmpStrLen = sprintf(str + strLen, " [%s]", file);
	strLen += tmpStrLen;

	//加入LOG发生行数
	tmpStrLen = sprintf(str + strLen, " [%d]\n", line);
	strLen += tmpStrLen;

	//打开LOG文件
	if (Error_OpenFile(&pf))
	{
		return;
	}

	//写入LOG文件
	write(pf, str, strLen);
	//Log_Error_WriteFile(str);

	//关闭文件
	close(pf);

	return;
}


void LOG(const char *file, int line, int level, int status, const char *fmt, ...)
{
	va_list args;

	//判断是否需要写LOG
	//	if(level!=DEBUG_LEVEL && level!=INFO_LEVEL && level!=WARNING_LEVEL && level!=ERROR_LEVEL)
	if (level == NO_LOG_LEVEL)
	{
		return;
	}

	//调用核心的写LOG函数
	va_start(args, fmt);
	Error_Core(file, line, level, status, fmt, args);
	va_end(args);

	return;
}

推荐阅读