moc 发表于 2018-8-22 21:14:26

021-日志函数及第二套api函数

1、日志库
        在函数出错或是调用调试时记录日志,是软件开发中的重要部分,下面是一套打印日志的函数,可以做成动态库。
        程序中存在着open()等文件操作函数,在win7 x64环境中运行不正常(日志文件不能正常生成);但业务逻辑可学习。
itcastlog.h
#ifndef _ITCAST_LOG_H_
#define _ITCAST_LOG_H_

/*
#define IC_NO_LOG_LEVEL                        0
#define IC_DEBUG_LEVEL                        1
#define IC_INFO_LEVEL                        2
#define IC_WARNING_LEVEL                3
#define IC_ERROR_LEVEL                        4;
*/

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

#endif
itcastlog.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 "ItcastLog.h"

#define ITCAST_DEBUG_FILE_        "socketclient.log"
#define ITCAST_MAX_STRING_LEN                 10240

//Level类别
#define IC_NO_LOG_LEVEL                        0
#define IC_DEBUG_LEVEL                        1
#define IC_INFO_LEVEL                        2
#define IC_WARNING_LEVEL                3
#define IC_ERROR_LEVEL                        4

intLogLevel = {IC_NO_LOG_LEVEL, IC_DEBUG_LEVEL, IC_INFO_LEVEL, IC_WARNING_LEVEL, IC_ERROR_LEVEL};

//Level的名称
char ICLevelName = {"NOLOG", "DEBUG", "INFO", "WARNING", "ERROR"};

static int ITCAST_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 ITCAST_Error_OpenFile(int* pf)
{
        char        fileName;
       
        memset(fileName, 0, sizeof(fileName));
#ifdef WIN32
        sprintf(fileName, "c:\\itcast\\%s",ITCAST_DEBUG_FILE_);
        printf("**x86**%s\n", fileName);// 说明我用的是x86环境
#else
        //sprintf(fileName, "%s/log/%s", getenv("HOME"), ITCAST_DEBUG_FILE_);
        sprintf(fileName, "c:\\itcast\\%s",ITCAST_DEBUG_FILE_);
        printf("**x64**%s\n", fileName);
#endif
   
    *pf = open(fileName, O_WRONLY|O_CREAT|O_APPEND, 0666);
    if(*pf < 0)
    {
      return -1;
    }       
        return 0;
}

static void ITCAST_Error_Core(const char *file, int line, int level, int status, const char *fmt, va_list args)
{
    char str;
    int       strLen = 0;
    char tmpStr;
    int       tmpStrLen = 0;
    intpf = 0;
   
    //初始化
    memset(str, 0, ITCAST_MAX_STRING_LEN);
    memset(tmpStr, 0, 64);
   
    //加入LOG时间
    tmpStrLen = ITCAST_Error_GetCurTime(tmpStr);
    tmpStrLen = sprintf(str, "[%s] ", tmpStr);
    strLen = tmpStrLen;

    //加入LOG等级
    tmpStrLen = sprintf(str+strLen, "[%s] ", ICLevelName);
    strLen += tmpStrLen;
   
    //加入LOG状态
    if (status != 0)
    {
      tmpStrLen = sprintf(str+strLen, " ", status);
    }
    else
    {
            tmpStrLen = sprintf(str+strLen, " ");
    }
    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(ITCAST_Error_OpenFile(&pf))
        {
                return ;
        }
       
    //写入LOG文件
    write(pf, str, strLen);
    //IC_Log_Error_WriteFile(str);
   
    //关闭文件
    close(pf);
   
    return ;
}

void ITCAST_LOG(const char *file, int line, int level, int status, const char *fmt, ...)
{
    va_list args;
       
        //判断是否需要写LOG
//        if(level!=IC_DEBUG_LEVEL && level!=IC_INFO_LEVEL && level!=IC_WARNING_LEVEL && level!=IC_ERROR_LEVEL)
        if(level == IC_NO_LOG_LEVEL)
        {
                return ;
        }
       
        //调用核心的写LOG函数
    va_start(args, fmt);
    ITCAST_Error_Core(file, line, level, status, fmt, args);
    va_end(args);
    return ;
}
2、第二套api的实现
调用该api函数
// 调用第二套api函数
voidmain()
{
        int ret = 0;
        void *handle = NULL;

        unsigned char buf;
        int buflen = 11;/*in*/

        unsigned char *out = NULL;
        int outlen = 0;

        strcpy(buf, "adddasdadddddddddasdada");
        // 客户端初始化
        ret = cltSocketInit2(&handle /*out*/);
        // 客户端发报文
        ret = cltSocketSend2(handle/*in*/, buf/*in*/, buflen/*in*/);
        // 客户端收报文
        ret = cltSocketRev2(handle/*in*/, &out, &outlen);
        ret = cltSocketRev2_Free(&out);//不但要把out所指向的内存空间释放,同样也把实参out赋成NULL,避免野指针
        //客户端释放资源
        if (handle != NULL)
        {
                cltSocketDestory2(&handle/*in*/);
        }

        system("pause");
}
第二套api函数的源码;该源码置于第一套之后,共同做成dll文件,用于别的函数调用。
//------------------第二套api接口---Begin--------------------------------//
//客户端初始化 获取handle上下
__declspec(dllexport)   //该语句的含义是下面的函数是向外抛出的函数
int cltSocketInit2(void **handle /*out*/)
{
        return cltSocketInit(handle);
}

//客户端发报文
__declspec(dllexport)
int cltSocketSend2(void *handle /*in*/, unsigned char *buf /*in*/, int buflen /*in*/)
{
        return cltSocketSend(handle, buf, buflen);
}

//客户端收报文
__declspec(dllexport)
int cltSocketRev2(void *handle /*in*/, unsigned char **buf /*in*/, int *buflen /*in out*/)
{
        int ret = 0;
        SCK_HANDLE *sh = NULL;
        unsigned char *tmp = NULL;
        if (handle == NULL || buf == NULL || buflen == NULL)
        {
                ret = -1;
                printf("func cltSocketRev2 error:%d", ret);
                return ret;
        }
        sh = (SCK_HANDLE *)handle;

        tmp = (char *)malloc(sh->buflen * sizeof(char));
        if (tmp == NULL)
        {
                ret = -1;
                printf("func cltSocketSend malloc error, buflen:%d", *buflen);
                return ret;
        }
        memcpy(tmp, sh->pbuf, sh->buflen);

        *buf = tmp;
        *buflen = sh->buflen;
        return ret;
}

__declspec(dllexport)
int cltSocketRev2_Free(unsigned char **buf)
{
        int ret = 0;
        if (buf == NULL)
        {
                ret = -1;
                printf("func cltSocketRev2_Free error:%d", ret);
                return ret;
        }
        free(*buf);
        *buf = NULL;// 释放的同时,也间接把实参修改啦

        return ret;
}

//客户端释放资源
__declspec(dllexport)
int cltSocketDestory2(void **handle/*in*/)
{
        int ret = 0;
        SCK_HANDLE *sh = NULL;
        if (handle == NULL)
        {
                ret = -1;
                printf("func cltSocketDestory error:%d", ret);
                return ret;
        }
        sh = (SCK_HANDLE *) *handle;

        if (sh->pbuf != NULL)
        {
                free(sh->pbuf);
        }
        free(sh);
        *handle = NULL;// 间接修改实参的值,避免野指针

        return ret;
}
//------------------第二套api接口---End-----------------------------------//

两套api函数的区别一个在主调函数中分配内存,一个在被调函数中分配内存。
另外:内存在哪里申请的的就要在哪里去释放,动态库里申请的内存就要调用动态库的函数去释放。
页: [1]
查看完整版本: 021-日志函数及第二套api函数