zoukankan      html  css  js  c++  java
  • 安全传输平台项目——客户端代码移植-项目模块总结

    在学习安全传输平台项目总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

    10-安全传输平台项目-第11天(客户端代码移植-项目模块总结)

    目录:
    一、复习
    二、安全传输平台项目——客户端代码移植-项目模块总结
    1、图形客户端-密钥协商组件分析
    2、图形客户端-物理组件集成
    3、图形客户端-Linux源码对接错误调试
    4、图形客户端-系统初始化
    5、图形客户端-删除控件对应函数
    6、图形客户端-密钥协商
    7、图形客户端-密钥协商内存释放错误说明
    8、总结
    9、接口设计
    10、文件加密原理
    11、文件加密函数源码
    12、数字证书、非对称加密

    一、复习

    1、复习-连接数据库
    2、复习-网点信息管理

    二、安全传输平台项目——客户端代码移植-项目模块总结

    1、图形客户端-密钥协商组件分析

    》SecMngClient协商客户端 界面设计及功能实现和SecMngServer配置管理 大体相同:

    1)打开“VS”,新建Dialog,ID更改为:IDD_DIALOG_CLIENT,布局如下:

    2)在“IDD_DIALOG_CLIENT”界面右键“添加类”,类名输入:CViewClient,基类选择:CFormView

    3)使用类向导,为ListCtrl添加成员变量:

    注意:自定义变量m_imageList不是通过类向导定义的,是通过代码定义的!

    4)在MainFrm.cpp中OnOutbarNotify函数中打开case代码,增加调用(去掉return 0)

    5)“类向导”中(ViewClient.cpp)重写OnInitialUpdate函数;和DlgNetInfo类似!

    6)在“IDD_DIALOG_CLIENT”界面中为按钮设置ID并添加回调函数

    回调函数的逻辑在Linux下已经做过:借助wind图形界面(客户端与服务器密钥协商、密钥校验、密钥注销)与linux客户端 文字界面(与 服务器密钥协商、密钥校验、密钥注销)逻辑一样,所以这块代码不用写了,把Linux下的代码移植过来。当然还需要更改!

    对比分析:

    》分析wind客户端和服务器 与 linux客户端和服务器 4大基础组件区别:
        1)统一报文编码解码    libmessagereal.so .h ---> .dll .lib .h
        2)统一通信组件socket    --- windows socket 通信        
        3)共享内存        --- windows shm 机制
        4)数据库访问    (客户端无需数据库)

    》代码如下:

    1)报文编解码_win

    >messagereal.dll

    >messagereal.lib

    >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];            //服务器端随机数
        int                    seckeyid;        //对称密钥编号 //modfy 2015.07.20
    }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
    keymng_msg.h

    2)共享内存_win_Linux

    >myipc_shm.h

    // myipc_shm.h
    #ifndef _WBM_MY_SHM_H_
    #define _WBM_MY_SHM_H_
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    #ifdef __cplusplus 
    extern "C" {
    #endif
    
    
    //共享内存错误码
    #define        MYIPC_OK                0        //正确
    #define        MYIPC_ParamErr            301        //输入参数失败
    #define        MYIPC_NotEXISTErr        302        //共享内存不存在错误
    #define        MYIPC_CreateErr            303        //创建共享内存错误
    
    
    //创建共享内存 若共享内存不存在,则创建
    int IPC_CreatShm(int key, int shmsize, int *shmhdl);
    
    //打开共享内存 若共享内存不存在,返回错误
    int IPC_OpenShm(int key, int shmsize, int *shmhdl);
    
    
    /***********************************************************************
      功能描述:    创建共享内存 通过种子文件
      参数说明:    shmname  [in]  是共享内存名,系统中唯一标志
                    shmsize  [in]  是要创建的共享内存的大小;
                    shmhdl   [out] 共享内存的句柄.
      返回值:      返回0函数执行成功;非0返回错误码
    ************************************************************************/
    int IPC_CreatShmBySeedName(char *shmname, int shmsize, int *shmhdl);
    
    /***********************************************************************
      功能描述:    关联共享内存
      参数说明:    shmhdl    [in]  共享的句柄
                    mapaddr [out] 共享内存首地址
      返回值:      返回0函数执行成功;非0返回错误码
    ************************************************************************/
    int IPC_MapShm(int shmhdl,void **mapaddr);
    
    
    /***********************************************************************
      功能描述:    取消共享内存关联
      参数说明:    unmapaddr   [in] 共享内存首地址
      返回值:      返回0函数执行成功;非0返回错误码
    ************************************************************************/
    int IPC_UnMapShm(void *unmapaddr);
    
    
    /***********************************************************************
      功能描述:    删除共享内存
      参数说明:    shmhdl    [in]  共享的句柄
      返回值:      返回0函数执行成功;非0返回错误码
    ************************************************************************/
    int IPC_DelShm(int shmhdl);
    
    
    #ifdef __cplusplus
    }
    #endif
    #endif
    myipc_shm.h

    >myipc_shm.cpp

    //#define    _OS_LINUX_
    
    #include "stdafx.h"
    
    #define    _OS_WIN_ 1
    #if defined _OS_WIN_
    #include <conio.h>
    #include <stdio.h>
    #include <memory.h>
    #include <string.h>
    #include <windows.h>
    #endif
    
    
    #if defined _OS_LINUX_
    #include <stdio.h>
    #include <errno.h>
    #include <unistd.h>
    #include <memory.h>
    #include <sys/ipc.h>
    #include <sys/shm.h>
    #include <sys/sem.h>
    #include <sys/msg.h>
    #include "myipc_shm.h" 
    
    #endif
    
    #include "myipc_shm.h"
    
    int shmflag = 0;
    int shmkey;
    
    
    //创建共享内存 若共享内存不存在,则创建 若存在使用原来的
    int IPC_CreatShm(int key, int shmsize, int *shmhdl)
    {
        int        tmpshmhdl = 0;
        int     ret = 0;
    #ifdef _OS_LINUX_
         //    创建共享内存 
         //    若共享内存不存在则创建 
         //    若共享内存已存在使用原来的
        tmpshmhdl = shmget(key, shmsize, IPC_CREAT|0666);
        if (tmpshmhdl == -1)            //创建失败
        {
            ret = MYIPC_ParamErr;
            printf("func shmget() err :%d ", ret);
            return ret;
        }
        *shmhdl = tmpshmhdl;
    #endif
    
    #ifdef _OS_WIN_
        char shmname[512] = {0};
        HANDLE m_hMapFile;
    
        sprintf(shmname, "%d", key);
    
         tmpshmhdl =(int)OpenFileMapping(FILE_MAP_WRITE, FALSE, shmname); 
         if (tmpshmhdl <= 0)
         {
            printf("共享内存不存在, 创建共享内存
    ");
            tmpshmhdl = (int)CreateFileMapping(    (HANDLE)0xFFFFFFFF,
                NULL,
                PAGE_READWRITE,
                0,
                shmsize,
                shmname);
            if ( tmpshmhdl == 0 )
            {
                return MYIPC_CreateErr;
            }
         }
         *shmhdl = tmpshmhdl;
    #endif
    
        return ret;
    }
    
    //打开共享内存 若共享内存不存在,返回错误
    //参数 无意义 可填写0
    int IPC_OpenShm(int key, int shmsize, int *shmhdl)
    {
        int        tmpshmhdl = 0;
        int     ret = 0;
    #ifdef _OS_LINUX_
         //    创建共享内存 
         //    若共享内存不存在则创建 
         //    若共享内存已存在使用原来的
        tmpshmhdl = shmget(key, 0, 0);
        if (tmpshmhdl == -1)            //打开失败
        {
            ret = MYIPC_NotEXISTErr;
            //printf("func shmget() err :%d ", ret);
            return ret;
        }
        *shmhdl = tmpshmhdl;
    #endif
    
    #ifdef _OS_WIN_
        char shmname[512] = {0};
        sprintf(shmname, "%d", key);
        tmpshmhdl = (int)OpenFileMapping(FILE_MAP_WRITE, FALSE, shmname);  //modify (int)
        if (tmpshmhdl <= 0)
        {
            ret = MYIPC_NotEXISTErr;
            //printf("func shmget() err :%d ", ret);
            return ret;
        }
        *shmhdl = tmpshmhdl;
    #endif
        return ret;
        
    }
    
    //   功能描述:    创建共享内存
    //   参数说明:    shmname  [in]  是共享内存名,系统中唯一标志
    //                 shmsize  [in]  是要创建的共享内存的大小;
    //                 shmhdl   [out] 共享内存的句柄.
    //   返回值:      返回0函数执行成功;非0返回错误码
    
    int IPC_CreatShmBySeedName(char *shmseedfile, int shmsize, int *shmhdl)
    {
        int        tmpshmhdl = 0;
        int     ret = 0;
    #ifdef _OS_LINUX_
        if(shmflag == 0)            //判断接口中共享内存key是否已经存在
        {
            shmkey = ftok(shmseedfile, 'c');
            if (shmkey == -1)
            {
                perror("ftok");
                return -1;
            }
                
            shmflag = 1;
        }
        
        //创建共享内存
        *shmhdl = shmget(shmkey,shmsize,IPC_CREAT|0666);
        if (*shmhdl == -1)            //创建失败
            return -2;
    #endif
    
    
    #ifdef _OS_WIN_
        tmpshmhdl = (int)CreateFileMapping(    (HANDLE)0xFFFFFFFF,
            NULL,
            PAGE_READWRITE,
            0,
            shmsize,
            shmseedfile);
        if ( tmpshmhdl == 0 )
        {
            return MYIPC_CreateErr;
        }
        *shmhdl = tmpshmhdl;
    #endif
        return 0;
    
    }
    
    //   功能描述:    关联共享内存
    //   参数说明:    shmhdl    [in]  共享的句柄
    //                 mapaddr [out] 共享内存首地址
    //   返回值:      返回0函数执行成功;非0返回错误码
    
    int
    IPC_MapShm(int  shmhdl, void  **mapaddr)
    {
        void *tempptr = NULL;
    
    #ifdef _OS_LINUX_
        //连接共享内存
        tempptr = (void *)shmat(shmhdl,0,SHM_RND);
        if ((int)tempptr == -1)        //共享内存连接失败
            return -1;
        *mapaddr = tempptr;            //导出共享内存首指针
    #endif
    
    #ifdef _OS_WIN_
        tempptr = MapViewOfFile((HANDLE)shmhdl,
            FILE_MAP_WRITE | FILE_MAP_READ, 
            0, 0, 0);
        if( tempptr == NULL )
            return -1;
    
        *mapaddr = tempptr;
    #endif
        return 0;
    }
    
    //   功能描述:    取消共享内存关联
    //   参数说明:    unmapaddr   [in] 共享内存首地址
    //   返回值:      返回0函数执行成功;非0返回错误码
    
    int IPC_UnMapShm(void *unmapaddr)
    {
        int  ret = 0;
    #ifdef _OS_LINUX_
        //取消连接共享内存 
        ret = shmdt((char *)unmapaddr);
        if (ret == -1)            //取消连接失败
            return -1;
    #endif
    
    #ifdef _OS_WIN_
        ret = UnmapViewOfFile(unmapaddr);
        if (ret == 0)
        {
            return -1;
        }
        else
        {
            return 0; //modify 
        }
            
    #endif
    
        return ret;
    }
    
    //   功能描述:    删除共享内存
    //   参数说明:    shmhdl    [in]  共享的句柄
    //   返回值:      返回0函数执行成功;非0返回错误码
    
    int IPC_DelShm(int shmhdl)
    {
        int  ret;
    
    #ifdef _OS_LINUX_
        //删除共享内存
        ret = shmctl(shmhdl,IPC_RMID,NULL);
        if(ret < 0)                //删除共享内存失败
            return -1;
    #endif
    
    #ifdef _OS_WIN_
        ret = CloseHandle((HANDLE)shmhdl);
        if (ret == 0)
            return -1;
    #endif
        return ret;
    }
    myipc_shm.cpp

    3)socket通信_win_Linux

    >poolsocket.h

    #ifndef _poolsocket_H_
    #define _poolsocket_H_
    
    
    //错误码定义  
    #define Sck_Ok                 0
    #define Sck_BaseErr           3000
    
    #define Sck_ErrParam                    (Sck_BaseErr+1)
    #define Sck_ErrTimeOut                    (Sck_BaseErr+2)
    #define Sck_ErrPeerClosed               (Sck_BaseErr+3)
    #define Sck_ErrMalloc                       (Sck_BaseErr+4)
    
    #define Sck_Err_Pool_CreateConn                (Sck_BaseErr+20)  //创建连接池 (没有达到最大连接数)
    #define Sck_Err_Pool_terminated                (Sck_BaseErr+21) //已终止
    #define Sck_Err_Pool_GetConn_ValidIsZero    (Sck_BaseErr+22) //有效连接数是零
    #define Sck_Err_Pool_HaveExist                (Sck_BaseErr+22) //连接已经在池中
    #define Sck_Err_Pool_ValidBounds            (Sck_BaseErr+22) //有效连接数目超过了最大连接数
    
    
    typedef struct _SCKClitPoolParam
    {
        char     serverip[64];
        int     serverport;
        int     bounds; //池容量
        int     connecttime;
        int     sendtime;
        int     revtime;
    }SCKClitPoolParam;
    
    
    //客户端 初始化
    int sckClient_init();
    
    //客户端 连接服务器
    int sckClient_connect(char *ip, int port, int connecttime, int *connfd);
    
    //客户端 关闭和服务端的连接
    int sckClient_closeconn(int connfd);
    
    //客户端 发送报文
    int sckClient_send(int connfd, int sendtime, unsigned char *data, int datalen);
    
    //客户端 接受报文
    int sckClient_rev(int connfd, int revtime, unsigned char **out, int *outlen); //1
    
    //客户端 释放内存
    int sck_FreeMem(void **buf);
    //客户端 释放
    int sckClient_destroy();
    
    
    //客户端 socket池初始化
    int sckCltPool_init(void **handle, SCKClitPoolParam *param);
    
    //客户端 socket池 获取一条连接 
    int sckCltPool_getConnet(void *handle, int *connfd);
    
    //客户端 socket池 发送数据 
    int sckCltPool_send(void *handle, int  connfd,  unsigned char *data, int datalen);
    
    //客户端 socket池 接受数据
    int sckCltPool_rev(void *handle, int  connfd, unsigned char **out, int *outlen); //1
    
    //客户端 socket池 把连接放回 socket池中 
    int sckCltPool_putConnet(void *handle, int connfd, int validFlag); //0正常 1
    
    //客户端 socket池 销毁连接
    int sckCltPool_destroy(void *handle);
    
    //函数声明
    //服务器端初始化
    int sckServer_init(int port, int *listenfd);
    
    int sckServer_accept(int listenfd, int timeout, int *connfd);
    //服务器端发送报文
    int sckServer_send(int connfd, int timeout, unsigned char *data, int datalen);
    //服务器端端接受报文
    int sckServer_rev(int  connfd, int timeout, unsigned char **out, int *outlen); //1
    
    int sckServer_close(int connfd);
    
    //服务器端环境释放 
    int sckServer_destroy();
    
    // #ifdef __cpluspluse
    // }
    // #endif
    #endif
    poolsocket.h

    >poolsocket.cpp

    // __declspec(dllexport)
    /*
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <signal.h>
    #include <sys/wait.h>
    
    #include <fcntl.h>
    #include <sys/time.h>
    #include <sys/time.h>
    */
    #include "stdafx.h"
    #include "windows.h"
    #include "winbase.h"
    #include <process.h>
    
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    //#include <pthread.h>
    
    #include "poolsocket.h"
    #include "socketlog.h"
    
    //Socket连接池结构
    typedef struct _SockePoolHandle
    {
        int *            fdArray;            //Socket连接池
        int    *            statusArray;        //每条连接的状态  eg: statusArray[0] =  1表示 链接有效 statusArray[0] =  0表示 链接无效
        int                valid;                //Socket有效连接数目 
        int                nvalid;                //Socket无效连接数目 
        int                bounds;                //Socket连接池的容量
        
        char             serverip[128];
        int             serverport;
        
        int             connecttime;
        int             sendtime;
        int             revtime;
        int                sTimeout; //没有连接时,等待之间
        //pthread_mutex_t foo_mutex ;
        LPCRITICAL_SECTION pCS ;  
        //判断连接池是否已经终止
        int                terminated;  //1已经终止 0没有终止
    }SockePoolHandle;
    
    
    //客户端 socket池初始化
    int sckCltPool_init(void **handle, SCKClitPoolParam *param)
    {
        int        ret =  0, i = 0;
        
        SockePoolHandle *hdl = NULL;
        
        //初始化 句柄
        hdl = (SockePoolHandle *)malloc(sizeof(SockePoolHandle));
        if (hdl == NULL)
        {
            ret = Sck_ErrMalloc;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckCltPool_init(), check malloc err");
            return ret;
        }
        memset(hdl, 0, sizeof(hdl));
        
        strcpy(hdl->serverip, param->serverip);
        hdl->serverport = param->serverport;
        
        hdl->connecttime = param->connecttime;
        hdl->sendtime = param->sendtime;
        hdl->revtime = param->revtime;
        
        //处理连接数
        hdl->bounds  = param->bounds;
        hdl->valid = 0;
        hdl->nvalid = param->bounds;
        hdl->sTimeout = 1;
    
        hdl->pCS = (LPCRITICAL_SECTION)malloc(sizeof(CRITICAL_SECTION));
        if (hdl->pCS==NULL)
        {       
            ret = Sck_ErrMalloc;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckCltPool_init(), check malloc err");
            return ret;
        }
        InitializeCriticalSection(hdl->pCS); //初始化
        EnterCriticalSection(hdl->pCS);
             
        //为连接句柄分配内存
        hdl->fdArray = (int *)malloc( hdl->bounds  * sizeof(int) );
        if (hdl->fdArray == NULL)
        {
            ret = Sck_ErrMalloc;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckCltPool_init(), check malloc err");
            goto END;
        }
        hdl->statusArray = (int *)malloc( hdl->bounds  * sizeof(int) );
        if (hdl->statusArray == NULL)
        {
            ret = Sck_ErrMalloc;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckCltPool_init(), check malloc err");
            goto END;
        }
        
        ret = sckClient_init();
        if (ret != 0)
        {
            printf("func sckClient_init() err:%d
    ", ret);
            goto END;
        }
        
        for (i=0; i<hdl->bounds; i++)
        {
            ret = sckClient_connect(hdl->serverip, hdl->serverport , hdl->connecttime , &(hdl->fdArray[i]) );
            if (ret != 0)
            {
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckClient_connect() err");
                break;
            }
            else
            {
                hdl->statusArray[i] = 1;
                hdl->valid ++;            //Socket有效连接数目
                hdl->nvalid --;            //Socket无效连接数目
            }
        }
        
        if (hdl->valid < hdl->bounds ) //若有效连接数 小于 总数
        {
            ret = Sck_Err_Pool_CreateConn;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"有效连接数 小于 总数");
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckClient_init() create connect num err:%d,  hdl->valid: %d , hdl->bounds:%d", ret, hdl->valid,   hdl->bounds);    
            for (i=0; i<hdl->bounds; i++)
            {
                if (hdl->statusArray[i] == 1)
                {
                    sckClient_closeconn(hdl->fdArray[i]);
                }
            }
        }
        
    END:    
        //pthread_mutex_unlock(& (hdl->foo_mutex) ); //解锁
        LeaveCriticalSection(hdl->pCS);
        if (ret != 0)
        {
            if (hdl->fdArray != NULL)         free(hdl->fdArray);
            if (hdl->statusArray != NULL)     free(hdl->statusArray);
            free(hdl);
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func pthread_mutex_unlock() err");
            return ret;
        }
        
        *handle = hdl; //间接赋值
        return ret;    
    }
    
    //客户端 socket池 获取一条连接 
    int sckCltPool_getConnet(void *handle, int *connfd)
    {
        int        ret =  0;
        
        SockePoolHandle *hdl = NULL;
        
        if (handle == NULL || connfd==NULL)
        {
            ret = Sck_ErrParam;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckCltPool_getConnet() (handle == NULL || connfd==NULL) err");
            return ret;
        }
        
        hdl = (SockePoolHandle *)handle;
        //pthread_mutex_lock( &(hdl->foo_mutex) ); //流程加锁 pthread_mutex_unlock(& (hdl->foo_mutex) ); //解锁
        EnterCriticalSection(hdl->pCS);
        
        
        //若 已终止
        if (hdl->terminated == 1)
        {
            ret = Sck_Err_Pool_terminated;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckCltPool_getConnet() (terminated == 1)");
            goto END;
        }
        
        //若 有效连数 = 0
        if (hdl->valid == 0)
        {
            //usleep(hdl->sTimeout); //等上几微妙
            Sleep(hdl->sTimeout);
            
            if (hdl->valid == 0)
            {
                ret = Sck_Err_Pool_GetConn_ValidIsZero;
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckCltPool_getConnet() Sck_Err_Pool_GetConn_ValidIsZero err");
                goto END;
            }
            
            //若 已终止
            if (hdl->terminated == 1)
            {
                ret = Sck_Err_Pool_terminated;
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckCltPool_getConnet() (terminated == 1)");
                goto END;
            }
        }
            
        //判断现有连接的状态
        if (hdl->statusArray[hdl->valid-1] == 0 )
        {
            //首先断开坏掉的连接
            if (hdl->fdArray[hdl->valid-1] == 0)
            {
                ret = sckClient_closeconn(hdl->fdArray[hdl->valid-1]);
                if (ret != 0)
                {
                    Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"funcsckClient_closeconn()err");
                    hdl->fdArray[hdl->valid-1] = 0;
                    //出错不做错误处理
                }
            }
        
            //断链修复 重新连接 1次
            ret = sckClient_connect(hdl->serverip, hdl->serverport, hdl->connecttime, &(hdl->fdArray[hdl->valid-1]) );
            if (ret != 0)
            {
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret," func sckClient_connect() err 断链修复 重新连接失败");
                hdl->fdArray[hdl->valid-1] = 0;
                goto END;
            }
        }
        
    END:
        if (ret == 0)
        {
            *connfd = hdl->fdArray[ --(hdl->valid) ]; //注 有效连接数 减1
        }
        
        //pthread_mutex_unlock(& (hdl->foo_mutex) ); //解锁
        //printf("valid=%d;nvalid=%d;bounds=%d 
    ", hdl->valid, hdl->nvalid, hdl->bounds);
        LeaveCriticalSection(hdl->pCS);
        return ret;    
    }
    
    //客户端 socket池 发送数据 
    int sckCltPool_send(void *handle, int  connfd,  unsigned char *data, int datalen)
    {
        int        ret =  0;
        SockePoolHandle *hdl = NULL;
        
        if (handle==NULL || connfd<0 || data==NULL || datalen<=0 )
        {
            ret = Sck_ErrParam;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret," func sckCltPool_send() err (handle==NULL || connfd<0 || data==NULL || datalen<=0) ");
            return ret;
        }
        hdl = (SockePoolHandle *)handle;
        
        //客户端 发送报文
        ret = sckClient_send(connfd, hdl->sendtime , data, datalen);
        if (ret != 0)
        {
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret," func sckClient_send() err");
            return ret;
        }
        
        return ret;    
    }
    
    //客户端 socket池 接受数据
    int sckCltPool_rev(void *handle, int  connfd, unsigned char **out, int *outlen)
    {
        int        ret =  0;
        SockePoolHandle *hdl = NULL;
        
        if (handle==NULL || connfd<0 || out==NULL || outlen==NULL )
        {
            ret = Sck_ErrParam;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret," func sckCltPool_rev() err, check (handle==NULL || connfd<0 || out==NULL || outlen==NULL )");
            return ret;
        }
        hdl = (SockePoolHandle *)handle;
        
        //客户端 接受报文
        ret = sckClient_rev(connfd, hdl->revtime,  out,  outlen); //1
        if (ret != 0)
        {
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret," func sckClient_rev() err");
            return ret;
        }
        
        return ret;    
    }
    
    //客户端 socket池 把连接放回 socket池中 
    int sckCltPool_putConnet(void *handle, int connfd, int validFlag)
    {
        int        ret =  0, i = 0;
    
        SockePoolHandle *hdl = NULL;
        
        if (handle == NULL || connfd<0)
        {
            ret = Sck_ErrParam;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret," func sckCltPool_putConnet() err, check (handle == NULL || connfd==NULL)");
            goto END;
        }
        
        hdl = (SockePoolHandle *)handle;
        //pthread_mutex_lock( &(hdl->foo_mutex) ); //流程加锁 
        EnterCriticalSection(hdl->pCS);
        
        //若 已终止
        if (hdl->terminated == 1)
        {
            ret = Sck_Err_Pool_terminated;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret," func sckCltPool_putConnet() err, check (func sckCltPool_putConnet() (terminated == 1))");
            hdl->fdArray[hdl->valid] = connfd;
            hdl->valid++;
            goto END;
        }
        
        //判断连接是否已经被 放进来         //判断该连接是否已经被释放
        for(i=0; i<hdl->valid; i++)
        {
            if (hdl->fdArray[i] == connfd)
            {
                ret = Sck_Err_Pool_HaveExist;
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret," func sckCltPool_putConnet() err, check Sck_Err_Pool_HaveExist ");
                goto END;
            }
        }
        
        //判断有效连接数是否已经到达最大值
        if (hdl->valid >= hdl->bounds)
        {
            ret = Sck_Err_Pool_ValidBounds ; 
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret," func sckCltPool_putConnet() err, check (hdl->valid >= hdl->bounds) ");
            goto END;
        }
        
        //判断释放的连接是否有效
        if (validFlag == 1)
        {
            hdl->fdArray[hdl->valid] = connfd;
            hdl->statusArray[hdl->valid] = 1; //连接有效
            hdl->valid++;  //
        }
        else
        {
            int tmpconnectfd = 0;
            //首先断开坏掉的连接
            ret = sckClient_closeconn(connfd);
            if (ret != 0)
            {
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret," func sckClient_closeconn() err, check (hdl->valid >= hdl->bounds) ");
                //失败不处理
            }
            
            //断链修复 重新连接 1次 若重新连接成功则再加入连接池中;若重新连接失败,则不需要加入到连接池中
            ret = sckClient_connect(hdl->serverip, hdl->serverport, hdl->connecttime, &tmpconnectfd );
            if (ret != 0)
            {
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret," func sckClient_connect() err, 断链修复 重新连接失败");
            }
            else    
            {
                //有效连接数加1
                hdl->fdArray[hdl->valid] = tmpconnectfd;
                hdl->statusArray[hdl->valid] = 1; //连接有效
                hdl->valid++;  //
            }
        }
    
    END:
        
        //pthread_mutex_unlock(& (hdl->foo_mutex) ); //解锁
        LeaveCriticalSection(hdl->pCS);
        //printf("valid=%d;nvalid=%d;bounds=%d 
    ", hdl->valid, hdl->nvalid, hdl->bounds);
    
        return ret;    
    }
    
    //客户端 socket池 销毁连接
    int sckCltPool_destroy(void *handle)
    {
        int        ret =  0, i = 0;
    
        SockePoolHandle *hdl = NULL;
        
        if (handle == NULL )
        {
            ret = Sck_ErrParam;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret," func sckCltPool_destroy() err, check (handle == NULL)");
            return ret;
        }
        
        hdl = (SockePoolHandle *)handle;
        //pthread_mutex_lock( &(hdl->foo_mutex) ); //流程加锁 
        EnterCriticalSection(hdl->pCS);
        
        //若 已终止
        hdl->terminated = 1; //连接池设置成终止 状态
        
        
        for (i=0; i<hdl->bounds; i++)
        {
            if (hdl->fdArray[i] != 0)
            {
                sckClient_closeconn(hdl->fdArray[i]);
            }
        }
        
        if (hdl->fdArray) 
        {
            free(hdl->fdArray); hdl->fdArray = NULL;
        }
        
        if (hdl->statusArray)
        {
            free(hdl->statusArray); hdl->statusArray = NULL;
        }
    
        sckClient_destroy();
        //pthread_mutex_unlock(& (hdl->foo_mutex) ); //解锁
        LeaveCriticalSection(hdl->pCS);
        free(hdl->pCS);
        free(hdl);
    
        //printf("valid=%d;nvalid=%d;bounds=%d 
    ", hdl->valid, hdl->nvalid, hdl->bounds);
        
        return ret;    
    }
    poolsocket.cpp

    >socketlog.h

    //socketlog.h 日志头文件
    
    #ifndef _SOCKET_LOG_H_
    #define _SOCKET_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 int  SocketLevel[5];
    void Socket_Log(const char *file, int line, int level, int status, const char *fmt, ...);
    
    #endif
    socketlog.h

    >socketlog.cpp

    #include "stdafx.h"
    #define  _CRT_SECURE_NO_WARNINGS 
    
    #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 "socketlog.h"
    
    #define ITCAST_DEBUG_FILE_    "socketlib.log"
    #define ITCAST_MAX_STRING_LEN         10240
    //#define WIN32
    
    //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
    
    int  SocketLevel[5] = {IC_NO_LOG_LEVEL, IC_DEBUG_LEVEL, IC_INFO_LEVEL, IC_WARNING_LEVEL, IC_ERROR_LEVEL};
    
    //Level的名称
    char ICLevelName[5][10] = {"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[1024];
        
        memset(fileName, 0, sizeof(fileName));
    #ifdef WIN32
        sprintf(fileName, "c:\itcast\%s",ITCAST_DEBUG_FILE_);
    #else
        sprintf(fileName, "%s/log/%s", getenv("HOME"), ITCAST_DEBUG_FILE_);
    #endif
        
        /*
        *pf = open(fileName, O_WRONLY|O_CREAT|O_APPEND, 0666);
        if(*pf < 0)
        {
            return -1;
        }
        */
        *pf = (int)fopen(fileName, "w+");
        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[ITCAST_MAX_STRING_LEN];
        int     strLen = 0;
        char tmpStr[64];
        int     tmpStrLen = 0;
        int  pf = 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[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]
    ", line);
        strLen += tmpStrLen;
        
        //打开LOG文件
        if(ITCAST_Error_OpenFile(&pf))
        {
            return ;
        }
        
        //写入LOG文件
       // write(pf, str, strLen);
        fwrite(str, 1, strLen, (FILE *)pf);
        //IC_Log_Error_WriteFile(str);
        
        //关闭文件
        fclose((FILE *)pf);
        
        return ;
    }
    
    
    void Socket_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 ;
    }
    socketlog.cpp

    >socketutil.h

    // socketutil.h
    
    #ifndef _socketutil_H_
    #define _socketutil_H_
    
    #ifdef __cplusplus
    extern 'C'
    {
    #endif
    
    #include <stdio.h>
    #include <stdlib.h>
    
    void activate_nonblock(int fd);
    void deactivate_nonblock(int fd);
    
    int read_timeout(int fd, unsigned int wait_seconds);
    int write_timeout(int fd, unsigned int wait_seconds);
    int accept_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds);
    int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds);
    
    
    int readn(int fd, void *buf, size_t count);
    int writen(int fd, const void *buf, size_t count);
    int recv_peek(int sockfd, void *buf, size_t len);
    int readline(int sockfd, void *buf, size_t maxline);
    
    
    #ifdef __cpluspluse
    }
    #endif
    
    
    #endif /* _SYS_UTIL_H_ */
    socketutil.h

    >socketutil.cpp

    #include "stdafx.h"
    #include <stdlib.h>
    #include <stdio.h>
    
    
    #include <winsock2.h>
    #include <stdio.h>
    #include <string.h>
    #include <time.h>
    #include <errno.h>
    
    
    #include "poolsocket.h"
    #include "socketlog.h"
    
    #define ssize_t int 
    #define socklen_t int 
    
    //
    //readn - 读取固定字节数
    //@fd: 文件描述符
    //@buf: 接收缓冲区
    //@count: 要读取的字节数
    //成功返回count,失败返回-1,读到EOF返回<count
    //
    int readn(int fd, void *buf, size_t count)
    {
        size_t nleft = count;
        int nread;
        char *bufp = (char*)buf;
    
        while (nleft > 0)
        {
            //if ((nread = read(fd, bufp, nleft)) < 0)
            if ((nread = recv(fd, bufp, nleft, 0)) < 0)
            {
                if (errno == EINTR)
                    continue;
                return -1;
            }
            else if (nread == 0)
                return count - nleft;
    
            bufp += nread;
            nleft -= nread;
        }
    
        return count;
    }
    
    //
    //writen - 发送固定字节数
    //@fd: 文件描述符
    //@buf: 发送缓冲区
    //@count: 要读取的字节数
    //成功返回count,失败返回-1
    //
    int writen(int fd, const void *buf, size_t count)
    {
        size_t nleft = count;
        ssize_t nwritten;
        char *bufp = (char*)buf;
    
        while (nleft > 0)
        {
            //if ((nwritten = write(fd, bufp, nleft)) < 0)
            if ((nwritten = send(fd, bufp, nleft, 0)) < 0)
            {
                if (errno == EINTR)
                    continue;
                return -1;
            }
            else if (nwritten == 0)
                continue;
    
            bufp += nwritten;
            nleft -= nwritten;
        }
    
        return count;
    }
    
    //
    //recv_peek - 仅仅查看套接字缓冲区数据,但不移除数据
    //@sockfd: 套接字
    //@buf: 接收缓冲区
    //@len: 长度
    //成功返回>=0,失败返回-1
    //
    int recv_peek(int sockfd, void *buf, size_t len)
    {
        while (1)
        {
            int ret = recv(sockfd, (char *)buf, len, MSG_PEEK);
            if (ret == -1 && errno == EINTR)
                continue;
            return ret;
        }
    }
    
    //
    //activate_noblock - 设置I/O为非阻塞模式
    //@fd: 文件描符符
    //
    int activate_nonblock(int fd)
    {
        int ret = 0;
        /*
        int flags = fcntl(fd, F_GETFL);
        if (flags == -1)
        {
            ret = flags;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func activate_nonblock() err");
            return ret;
        }
            
        flags |= O_NONBLOCK;
        ret = fcntl(fd, F_SETFL, flags);
        if (ret == -1)
        {
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func activate_nonblock() err");
            return ret;
        }
        */
    
        
        int flags = 1;
        if (ioctlsocket(fd, FIONBIO, (u_long *)&flags))
        {
            ret = -1;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func ioctlsocket() err 设置为非阻塞模式失败");
            return ret;
        }
        return ret;
    }
    
    //
    //deactivate_nonblock - 设置I/O为阻塞模式
    //@fd: 文件描符符
    //
    int deactivate_nonblock(int fd)
    {
        int ret = 0;
        /*
        int flags = fcntl(fd, F_GETFL);
        if (flags == -1)
        {
            ret = flags;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func deactivate_nonblock() err");
            return ret;
        }
    
        flags &= ~O_NONBLOCK;
        ret = fcntl(fd, F_SETFL, flags);
        if (ret == -1)
        {
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func deactivate_nonblock() err");
            return ret;
        }*/
    
        int flags = 0;
        if(ioctlsocket(fd, FIONBIO, (u_long *)&flags))
        {
            ret = -1;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret, "func ioctlsocket() err 设置为阻塞模式失败 ");
            return ret;
        }
        
        
        return ret;
    }
    
    //
    //connect_timeout - connect
    //@fd: 套接字
    //@addr: 要连接的对方地址
    //@wait_seconds: 等待超时秒数,如果为0表示正常模式
    //成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT
    //
    static int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds)
    {
        int ret;
        socklen_t addrlen = sizeof(struct sockaddr_in);
    
        if (wait_seconds > 0)
            activate_nonblock(fd);
    
        ret = connect(fd, (struct sockaddr*)addr, addrlen);
        if (ret < 0 && errno == EINPROGRESS  ||
            ret<0 && WSAGetLastError()==WSAEWOULDBLOCK ) //win和linux下
        {
            //printf("11111111111111111111
    ");
            fd_set connect_fdset;
            struct timeval timeout;
            FD_ZERO(&connect_fdset);
            FD_SET(fd, &connect_fdset);
            timeout.tv_sec = wait_seconds;
            timeout.tv_usec = 0;
            do
            {
                // 一但连接建立,则套接字就可写  所以connect_fdset放在了写集合中
                ret = select(fd + 1, NULL, &connect_fdset, NULL, &timeout);
            } while (ret < 0 && errno == EINTR);
            if (ret == 0)
            {
                ret = -1;
                errno = ETIMEDOUT;
            }
            else if (ret < 0)
                return -1;
            else if (ret == 1)
            {
                //printf("22222222222222222
    ");
                // ret返回为1(表示套接字可写),可能有两种情况,一种是连接建立成功,一种是套接字产生错误,
                // 此时错误信息不会保存至errno变量中,因此,需要调用getsockopt来获取。 
                int err;
                socklen_t socklen = sizeof(err);
                int sockoptret = getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&err, &socklen);
                if (sockoptret == -1)
                {
                    return -1;
                }
                if (err == 0)
                {
                    //printf("3333333333333
    ");
                    ret = 0;
                }
                else
                {
                    //printf("4444444444444444:%d
    ", err);
                    errno = err;
                    ret = -1;
                }
            }
        }
        
        
        if (wait_seconds > 0)
        {
            deactivate_nonblock(fd);
        }
        return ret;
    }
    
    
    //
    //write_timeout - 写超时检测函数,不含写操作
    //@fd: 文件描述符
    //@wait_seconds: 等待超时秒数,如果为0表示不检测超时
    //成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT
    //
    int write_timeout(int fd, unsigned int wait_seconds)
    {
        int ret = 0;
        if (wait_seconds > 0)
        {
            fd_set write_fdset;
            struct timeval timeout;
    
            FD_ZERO(&write_fdset);
            FD_SET(fd, &write_fdset);
    
            timeout.tv_sec = wait_seconds;
            timeout.tv_usec = 0;
            do
            {
                ret = select(fd + 1, NULL, &write_fdset, NULL, &timeout);
            } while (ret < 0 && errno == EINTR);
    
            if (ret == 0)
            {
                ret = -1;
                errno = ETIMEDOUT;
            }
            else if (ret == 1)
                ret = 0;
        }
    
        return ret;
    }
    
    
    //
    //read_timeout - 读超时检测函数,不含读操作
    //@fd: 文件描述符
    //@wait_seconds: 等待超时秒数,如果为0表示不检测超时
    //成功(未超时)返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT
    //
    int read_timeout(int fd, unsigned int wait_seconds)
    {
        int ret = 0;
        if (wait_seconds > 0)
        {
            fd_set read_fdset;
            struct timeval timeout;
    
            FD_ZERO(&read_fdset);
            FD_SET(fd, &read_fdset);
    
            timeout.tv_sec = wait_seconds;
            timeout.tv_usec = 0;
            
            //select返回值三态
            //1 若timeout时间到(超时),没有检测到读事件 ret返回=0
            //2 若ret返回<0 &&  errno == EINTR 说明select的过程中被别的信号中断(可中断睡眠原理)
            //2-1 若返回-1,select出错
            //3 若ret返回值>0 表示有read事件发生,返回事件发生的个数
            
            do
            {
                ret = select(fd + 1, &read_fdset, NULL, NULL, &timeout);
            } while (ret < 0 && errno == EINTR); 
    
            if (ret == 0)
            {
                ret = -1;
                errno = ETIMEDOUT;
            }
            else if (ret == 1)
                ret = 0;
        }
    
        return ret;
    }
    
    
    
    //函数声明
    //客户端环境初始化
    int sckClient_init()
    {
        int        ret = 0;
        WSADATA wsaData;
    
        struct sockaddr_in servaddr;
    
        ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (ret != NO_ERROR)
        {
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func WSAStartup() err");
            return ret;
        }
        return 0; 
    }
    
    
    int sckClient_connect(char *ip, int port, int connecttime, int *connfd)
    {
        
        int                    ret = 0;
        int                    sockfd;
        struct sockaddr_in    servaddr;
    
        if (ip==NULL || connfd==NULL || port<=0 || port>65537 || connecttime < 0)
        {
            ret = Sck_ErrParam;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckClient_connect() err, check  (ip==NULL || connfd==NULL || port<=0 || port>65537 || connecttime < 0)");
            return ret;
        }
        
        //
        
        sockfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
        if (sockfd < 0)
        {
            ret = errno;
            printf("func socket() err:  %d
    ", ret);
            return ret;
        }
        
        
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(port);
        servaddr.sin_addr.s_addr = inet_addr(ip);
        
        ret = connect_timeout(sockfd, (struct sockaddr_in*) (&servaddr), (unsigned int )connecttime);
        if (ret < 0)
        {
            if (ret==-1 && errno == ETIMEDOUT)
            {
                ret = Sck_ErrTimeOut;
                return ret;
            }
            else
            {
                printf("func connect_timeout() err:  %d
    ", ret);
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func connect_timeout() err");
            }
            return ret;
        }
        
        *connfd = sockfd;
       
           return ret;
        
    }
    
    
    //客户端发送报文
    int sckClient_send(int connfd, int sendtime, unsigned char *data, int datalen)
    {
        int     ret = 0;
        
        if (data == NULL || datalen <= 0)
        {
            ret = Sck_ErrParam;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckClient_send() err, check (data == NULL || datalen <= 0)");
            return ret;
        } 
        
        ret = write_timeout(connfd, sendtime);
        if (ret == 0)
        {
            int writed = 0;
            int netlen = 0;
            unsigned char *netdata = ( unsigned char *)malloc(datalen + 4);
            if ( netdata == NULL)
            {
                ret = Sck_ErrMalloc;
                printf("func sckClient_send() mlloc Err:%d
     ", ret);
                return ret;
            }
            netlen = htonl(datalen);
            memcpy(netdata, &netlen, 4);
            memcpy(netdata+4, data, datalen);
            
            //writed = writen(connfd, netdata, datalen + 4);
            writed = send(connfd, (const char *)netdata, datalen + 4, 0);
            if (writed < (datalen + 4) )
            {
                if (netdata != NULL) 
                {
                    free(netdata);
                    netdata = NULL;
                }
                return writed;
            }
            
            if (netdata != NULL)  //wangbaoming 20150630 modify bug
            {
                free(netdata);
                netdata = NULL;
            }  
        }
        
        if (ret < 0)
        {
            //失败返回-1,超时返回-1并且errno = ETIMEDOUT
            if (ret == -1 && errno == ETIMEDOUT)
            {
                ret = Sck_ErrTimeOut;
                printf("func sckClient_send() mlloc Err:%d
     ", ret);
                return ret;
            }
            return ret;
        }
        
        return ret;
    }
    
    
    //客户端端接受报文
    int sckClient_rev(int connfd, int revtime, unsigned char **out, int *outlen)
    {
        
        int        ret = 0;
        unsigned char *tmpBuf = NULL;
    
        int netdatalen = 0;
        int n;
        
        if (out==NULL || outlen==NULL)
        {
            ret = Sck_ErrParam;
            printf("func sckClient_rev() timeout , err:%d 
    ", Sck_ErrTimeOut);
            return ret;
        }
        
        ret =  read_timeout(connfd, revtime ); //bugs modify bombing
        if (ret != 0)
        {
            if (ret==-1 || errno == ETIMEDOUT)
            {
                ret = Sck_ErrTimeOut;
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func read_timeout() timeout");
                return ret;
            }
            else
            {
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func read_timeout() err");
                return ret;
            }    
        }
        
        
        ret = readn(connfd, &netdatalen,  4); //读包头 4个字节
        if (ret == -1)
        {
            //printf("func readn() err:%d 
    ", ret);
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func readn() err");
            return ret;
        }
        else if (ret < 4)
        {
            ret = Sck_ErrPeerClosed;
            //printf("func readn() err peer closed:%d 
    ", ret);
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func readn() err, peer closed");
            return ret;
        }
        
        
        n = ntohl(netdatalen);
        tmpBuf = (unsigned char *)malloc(n+1);
        if (tmpBuf == NULL)
        {
            ret = Sck_ErrMalloc;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"malloc() err");
            return ret;    
        }
        
        
        ret = readn(connfd, tmpBuf, n); //根据长度读数据
        if (ret == -1)
        {
            //printf("func readn() err:%d 
    ", ret);
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"readn() err");
            return ret;
        }
        else if (ret < n)
        {
            ret = Sck_ErrPeerClosed;
            //printf("func readn() err peer closed:%d 
    ", ret);
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func readn() err,  peer closed");
            return ret;
        }
        
        *out = tmpBuf;
        *outlen = n;
        tmpBuf[n] = ''; //多分配一个字节内容,兼容可见字符串 字符串的真实长度仍然为n
        return 0;
    }
    
    
    //客户端 关闭与服务端的连接
    int sckClient_closeconn(int connfd)
    {
        if (connfd > 0 )
        {
            //close(connfd); 
            closesocket(connfd); 
        }
        return 0;
    }
    
    //客户端 释放内存
    int sck_FreeMem(void **buf)
    {
        if (buf == NULL)
        {
            return 0;
        }    
        if (*buf != NULL)
        {
            free (*buf);
        }
        *buf = NULL; //简介修改实参的值
        return 0;
    }
    
    // 客户端环境释放 
    int sckClient_destroy()
    {
        WSACleanup();
        return 0;
    }
    
    
    #pragma comment(lib,"ws2_32.lib") 
    
    /////////////////////////////////////////////////////////////////////////////////////
    //函数声明
    //服务器端初始化
    int sckServer_init(int port, int *listenfd)
    {
        int     ret = 0;
        int        mylistenfd;
        int        on = 1;
        WSADATA wsaData;
    
        struct sockaddr_in servaddr;
    
        ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
        if (ret != NO_ERROR)
        {
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func socket() err");
            return ret;
        }
    
        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(port);
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        
            
        mylistenfd = socket(PF_INET, SOCK_STREAM, 0);
        if (mylistenfd < 0)
        {
            ret = errno ; 
            WSACleanup();
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func socket() err");
            return ret;
        }
        
        ret = setsockopt(mylistenfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on) );
        if (ret < 0)
        {
            ret = errno ;
            WSACleanup();
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func setsockopt() err");
            return ret;
        }
        
    
        ret = bind(mylistenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
        if (ret < 0)
        {
            ret = errno ;
            WSACleanup();
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func bind() err");
            return ret;
        }
            
        ret = listen(mylistenfd, SOMAXCONN);
        if (ret < 0)
        {
            ret = errno ;
            WSACleanup();
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func listen() err");
            return ret;
        }
            
        *listenfd = mylistenfd;
    
        return 0;
    }
    
    
    //
    //accept_timeout - 带超时的accept
    //@fd: 套接字
    //@addr: 输出参数,返回对方地址
    //@wait_seconds: 等待超时秒数,如果为0表示正常模式
    //成功(未超时)返回已连接套接字,超时返回-1并且errno = ETIMEDOUT
    //
    int accept_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds)
    {
        int ret;
        //socklen_t addrlen = sizeof(struct sockaddr_in);
        int addrlen = sizeof(struct sockaddr_in);
    
        if (wait_seconds > 0)
        {
            fd_set accept_fdset;
            struct timeval timeout;
            FD_ZERO(&accept_fdset);
            FD_SET(fd, &accept_fdset);
            timeout.tv_sec = wait_seconds;
            timeout.tv_usec = 0;
            do
            {
                ret = select(fd + 1, &accept_fdset, NULL, NULL, &timeout);
            } while (ret < 0 && errno == EINTR);
            if (ret == -1)
                return -1;
            else if (ret == 0)
            {
                errno = ETIMEDOUT;
                return -1;
            }
        }
    
        //一但检测出 有select事件发生,表示对等方完成了三次握手,客户端有新连接建立
        //此时再调用accept将不会堵塞
        if (addr != NULL)
            ret = accept(fd, (struct sockaddr*)addr, &addrlen); //返回已连接套接字
        else
            ret = accept(fd, NULL, NULL);
            if (ret == -1)
            {
                ret = errno;
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func accept() err");
                return ret;
            }
        
    
        return ret;
    }
    
    int sckServer_accept(int listenfd,  int timeout, int *connfd)
    {
        int    ret = 0;
        
        ret = accept_timeout(listenfd, NULL, (unsigned int) timeout);
        if (ret < 0)
        {
            if (ret == -1 && errno == ETIMEDOUT)
            {
                ret = Sck_ErrTimeOut;
                //printf("func accept_timeout() timeout err:%d 
    ", ret);
                return ret;
            }
            else
            {
                ret = errno;
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func accept_timeout() err");
                return ret;
            }
        }
        
        *connfd = ret;
        return 0;
    }
    //服务器端发送报文
    int sckServer_send(int connfd, int timeout, unsigned char *data, int datalen)
    {
        int     ret = 0;
        
        ret = write_timeout(connfd, timeout);
        if (ret == 0)
        {
            int writed = 0;
            int netlen = 0;
            unsigned char *netdata = ( unsigned char *)malloc(datalen + 4);
            if ( netdata == NULL)
            {
                ret = Sck_ErrMalloc;
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func malloc() err");
                return ret;
            }
    
            netlen = htonl(datalen);
            memcpy(netdata, &netlen, 4);
            memcpy(netdata+4, data, datalen);
            
            //writed = writen(connfd, netdata, datalen + 4);
            writed = send(connfd, (const char *)netdata, datalen + 4, 0);
            if (writed < (datalen + 4) )
            {
                if (netdata != NULL) 
                {
                    free(netdata);
                    netdata = NULL;
                }
                return writed;
            }
              
        }
        
        if (ret < 0)
        {
            //失败返回-1,超时返回-1并且errno = ETIMEDOUT
            if (ret == -1 && errno == ETIMEDOUT)
            {
                ret = Sck_ErrTimeOut;
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckServer_send() err");
                return ret;
            }
            return ret;
        }
        
        return ret;
    }
    
    //服务器端端接受报文
    int sckServer_rev(int  connfd, int timeout, unsigned char **out, int *outlen)
    {
            
        int        ret = 0;
        unsigned char *tmpBuf = NULL;
        int netdatalen = 0;
        int n;
        
        if (out==NULL || outlen==NULL)
        {
            ret = Sck_ErrParam;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func sckServer_rev() err, check (out==NULL || outlen==NULL)");
            return ret;
        }
        
        ret =  read_timeout(connfd, timeout); //bugs modify bombing
        if (ret != 0)
        {
            if (ret==-1 || errno == ETIMEDOUT)
            {
                ret = Sck_ErrTimeOut;
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func read_timeout() err");
                return ret;
            }
            else
            {
                Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func read_timeout() err");
                return ret;
            }    
        }
        
        
        ret = readn(connfd, &netdatalen,  4); //读包头 4个字节
        if (ret == -1)
        {
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func readn() err");
            return ret;
        }
        else if (ret < 4)
        {
            ret = Sck_ErrPeerClosed;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func readn() err, peer closed");
            return ret;
        }
        
    
        n = ntohl(netdatalen);
        
        tmpBuf = (unsigned char *)malloc(n+1);
        if (tmpBuf == NULL)
        {
            ret = Sck_ErrMalloc;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func malloc() err");
            return ret;    
        }
        
        ret = readn(connfd, tmpBuf, n); // 服务端 根据长度读数据
        if (ret == -1)
        {
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func readn() err");
            return ret;
        }
        else if (ret < n)
        {
            ret = Sck_ErrPeerClosed;
            Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func readn() err. peer closed");
            return ret;
        }
        
        *out = tmpBuf; //间接赋值
        *outlen = n;
        tmpBuf[n] = '';
        
        return 0;
    }
    
    //服务器端 关闭连接
    int sckServer_close(int connfd)
    {
        //close(connfd);    
        closesocket(connfd);
        return 0;
    }
    
    //服务器端环境释放 
    int sckServer_destroy()
    {
        return 0;
    }
    socketutil.cpp

    2、图形客户端-物理组件集成

    》3大物理组件集成:

    (1)拷贝“报文编解码_win”目录下的(messagereal.dll、messagereal.lib、keymng_msg.h)3个文件到项目所在的目录,然后剪切messagereal.dll到项目目录的上一级目录的Debug目录下;然后在项目“MyAdmin”右键选择“添加现有项”添加keymng_msg.h文件;

    (2)在“资源视图”中项目“MyAdmin”右键选择“属性”,在左侧选择“链接器”的“输入”,然后在右侧“附加依赖项”的下拉框中编辑,添加:messagereal.lib,然后点击“确定”;

    (3)拷贝“共享内存_win_Linux”目录下的(myipc_shm.h、myipc_shm.cpp)2个文件到项目所在的目录;然后在项目“MyAdmin”右键选择“添加现有项”添加这2个文件;

    (4)拷贝“socket通信_win_Linux”目录下的(poolsocket.h、poolsocket.cpp、socketlog.h、socketlog.cpp、socketutil.h、socketutil.cpp)6个文件到项目所在的目录;然后在项目“MyAdmin”右键选择“添加现有项”添加这6个文件;

    》将 Linux 业务代码移植到win下:

    (1)wind新建文件夹“Linux-src”添加与客户端相关的源码:keymng_shmop.h、keymng_shmop.c、keymngclientop.h、keymngclientop.c、keymnglog.h、keymnglog.c

    (2)为支持VS的MFC中的cpp格式,所以把*.c改为*.cpp(如:keymng_shmop.c改为keymng_shmop.cpp);

    (3)拷贝“Linux-src”目录下的(keymng_shmop.h、keymng_shmop.cpp、keymngclientop.h、keymngclientop.cpp、keymnglog.h、keymnglog.cpp)6个文件到项目所在的目录;然后在项目“MyAdmin”右键选择“添加现有项”添加这6个文件;

    3、图形客户端-Linux源码对接错误调试

    (1)直接生成,项目报错如下:

    解决: 去除*.cpp文件 #include 中 Linux 专用 头文件;添加:

    #define  _CRT_SECURE_NO_WARNINGS
    #include "stdafx.h"

    >keymng_shmop.cpp:

    >keymngclientop.cpp:

    >keymnglog.cpp:


    (2)报错:未定义标识符:

    1)未定义标识符“open”:

    解决:keymnglog.cpp中open(fileName, O_WRONLY|O_CREAT|O_APPEND, 066);  →   (int) fopen(fileName,"w+");

     

    2)未定义标识符“write”:

    先注释掉,待解决;

    3)未定义标识符“write”:

    解决:keymnglog.cpp中close(fp);   →  fclose((int)pf);

    (3)报错:表达式必须是指向完整对象类型的指针,无法从“void”转换为“NodeSHMInfo”:

    解决:keymng_shmop.cpp中pNode = mapaddr + i*sizeof(NodeSHMInfo);   →    pNode = (NodeSHMInfo *)mapaddr + i*sizeof(NodeSHMInfo);

    keymng_shmop.cpp中90行、104行、146行共需要修改3处。

    (4)报错:ICLevelName已经在keymnglog.obj中定义,找到一个或多个多重定义的符号;

    解决:keymnglog.cpp中把ICLevelName修改为ICKeyMngLogName

    keymnglog.cpp中33行、88行共需要修改2处。

    4、图形客户端-系统初始化

    (1)修改“IDD_DIALOG_CLIENT”中 密钥协商按钮ID为:IDC_BUTTON_AGREE;密钥校验按钮ID为:IDC_BUTTON_CHECK;密钥注销按钮ID为:IDC_BUTTON_REVOKE;系统初始化按钮ID为:IDC_BUTTON_SYSINIT;

    (2)双击按钮,设置系统初始化的回调函数void CViewClient::OnBnClickedButtonSysinit()

    》注意:1)在ViewClient.cpp添加头文件#include "keymngclientop.h"

    2)定义全局的MngClient_Info pCltInfo;

    3)更改keymngclientop.cpp中ip:strcpy(pCltInfo->serverip, "192.168.22.251");

    附:密钥协商、密钥校验、密钥注销、系统初始化 回调函数

    >ViewClient.h

    #pragma once
    #include "afxcmn.h"
    
    // CViewClient 窗体视图
    
    class CViewClient : public CFormView
    {
        DECLARE_DYNCREATE(CViewClient)
    
    protected:
        CViewClient();           // 动态创建所使用的受保护的构造函数
        virtual ~CViewClient();
    
    public:
        enum { IDD = IDD_DIALOG_CLIENT };
    #ifdef _DEBUG
        virtual void AssertValid() const;
    #ifndef _WIN32_WCE
        virtual void Dump(CDumpContext& dc) const;
    #endif
    #endif
    
    protected:
        virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
    
        DECLARE_MESSAGE_MAP()
    public:
        virtual void OnInitialUpdate();
        CListCtrl m_listSecNode;
    
    public:
        CImageList        m_imageList;
        int CViewClient::DbInitListSecNode(CString &clientid, CString &serverid, int keyid, int state, CTime &time);
        afx_msg void OnBnClickedButtonAgree();
        afx_msg void OnBnClickedButtonSysinit();
        afx_msg void OnBnClickedButtonCheck();
    };
    ViewClient.h

    >ViewClient.cpp

    // ViewClient.cpp : 实现文件
    //
    
    #include "stdafx.h"
    #include "MyAdmin.h"
    #include "ViewClient.h"
    #include "keymngclientop.h"
    #include "keymng_shmop.h"
    
    
    // CViewClient
    
    IMPLEMENT_DYNCREATE(CViewClient, CFormView)
    
    CViewClient::CViewClient()
        : CFormView(CViewClient::IDD)
    {
    
    }
    
    CViewClient::~CViewClient()
    {
    }
    
    void CViewClient::DoDataExchange(CDataExchange* pDX)
    {
        CFormView::DoDataExchange(pDX);
        DDX_Control(pDX, IDC_LIST_SECNODE, m_listSecNode);
    }
    
    BEGIN_MESSAGE_MAP(CViewClient, CFormView)
    
        ON_BN_CLICKED(IDC_BUTTON_AGREE, &CViewClient::OnBnClickedButtonAgree)
        ON_BN_CLICKED(IDC_BUTTON_SYSINIT, &CViewClient::OnBnClickedButtonSysinit)
        ON_BN_CLICKED(IDC_BUTTON_CHECK, &CViewClient::OnBnClickedButtonCheck)
    END_MESSAGE_MAP()
    
    
    // CViewClient 诊断
    
    #ifdef _DEBUG
    void CViewClient::AssertValid() const
    {
        CFormView::AssertValid();
    }
    
    #ifndef _WIN32_WCE
    void CViewClient::Dump(CDumpContext& dc) const
    {
        CFormView::Dump(dc);
    }
    #endif
    #endif //_DEBUG
    
    // CViewClient 消息处理程序
    
    int CViewClient::DbInitListSecNode(CString &clientid, CString &serverid, int keyid, int state, CTime &time)
    {
        // TODO:  在此添加控件通知处理程序代
        LVITEM   lvi;
        lvi.mask = LVIF_IMAGE | LVIF_TEXT;
        lvi.iItem = 0;    //在第几行上插入数据 始终头插法
        lvi.iImage = 4;
    
        //插入第0列数据
        lvi.iSubItem = 0;        // Set subitem 0
        lvi.pszText = (LPTSTR)(LPCTSTR)clientid;
        m_listSecNode.InsertItem(&lvi);
    
        ////插入第1列数据
        lvi.iSubItem = 1;        // Set subitem 1
        lvi.pszText = (LPTSTR)(LPCTSTR)serverid;
        m_listSecNode.SetItem(&lvi);
    
        char buf[128] = { 0 };
        sprintf(buf, "%d", keyid);
        ////插入第2列数据
        lvi.iSubItem = 2;        // Set subitem 1
        lvi.pszText = (LPTSTR)(LPCTSTR)buf;
        m_listSecNode.SetItem(&lvi);
    
        //插入第3列数据
        lvi.iSubItem = 3;        // Set subitem 3
        if (state == 1)
        {
            lvi.pszText = "禁用";
    
        }
        else {
            lvi.pszText = "正常";
        }
        m_listSecNode.SetItem(&lvi);
    
    
        //插入第4列数据
        CString strTime = time.Format("%Y-%m-%d %H:%M:%S");
        lvi.iSubItem = 4;        // Set subitem 4
        //CString strAuthcode(authcode) ;
        lvi.pszText = (LPTSTR)(LPCTSTR)strTime;
        m_listSecNode.SetItem(&lvi);
        return 0;
    }
    
    
    void CViewClient::OnInitialUpdate()
    {
        CFormView::OnInitialUpdate();
        HIMAGELIST hList = ImageList_Create(16, 16, ILC_COLOR8 | ILC_MASK, 8, 1);
        m_imageList.Attach(hList);
    
        CBitmap cBmp;
        cBmp.LoadBitmap(IDB_BITMAP_SECNODE);
        m_imageList.Add(&cBmp, RGB(255, 0, 255));
        cBmp.DeleteObject();
    
        m_listSecNode.SetImageList(&m_imageList, LVSIL_SMALL);
    
    
        DWORD dwExStyle = ListView_GetExtendedListViewStyle(m_listSecNode.m_hWnd);
        dwExStyle |= LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES;
        ListView_SetExtendedListViewStyle(m_listSecNode.m_hWnd, dwExStyle);
    
    
        CRect rect; //msdn
        m_listSecNode.GetClientRect(&rect);
        int nColInterval = rect.Width() / 5;
    
        m_listSecNode.SetRedraw(FALSE);
        m_listSecNode.InsertColumn(0, "Client编号", LVCFMT_LEFT, nColInterval);
        m_listSecNode.InsertColumn(1, "Server编号", LVCFMT_LEFT, nColInterval);
        m_listSecNode.InsertColumn(2, "当前密钥KeyId", LVCFMT_LEFT, nColInterval);
        m_listSecNode.InsertColumn(3, "密钥状态", LVCFMT_LEFT, nColInterval);
        m_listSecNode.InsertColumn(4, "请求时间", LVCFMT_LEFT, rect.Width() - 4 * nColInterval);
        m_listSecNode.SetRedraw(TRUE);
    
        CString clientid = "1111";
        CString serverid = "0001";
        int keyid = 105;
        int state = 0;
        CTime time = COleDateTime::GetCurrentTime();
    
        DbInitListSecNode(clientid, serverid, keyid, state, time);
    
    }
    
    MngClient_Info pCltInfo;
    
    void CViewClient::OnBnClickedButtonAgree()
    {
        // TODO: 在此添加控件通知处理程序代码
        int ret = 0;
        ret = MngClient_Agree(&pCltInfo);
        if (ret != 0)
        {
            AfxMessageBox("客户端密钥协商失败");
        }
        else
        {
            AfxMessageBox("客户端密钥协商成功");
        }
    }
    
    void CViewClient::OnBnClickedButtonSysinit()
    {
        // TODO: 在此添加控件通知处理程序代码
        int ret = 0;
    
        ret = MngClient_InitInfo(&pCltInfo);
        if (ret != 0)
        {
            AfxMessageBox("客户端系统初始化失败");
        }
        else
        {
            AfxMessageBox("客户端系统初始化成功");
        }
    }
    
    void CViewClient::OnBnClickedButtonCheck()
    {
        // TODO: 在此添加控件通知处理程序代码
        int ret = 0;
    
        ret = MngClient_Check(&pCltInfo);
        if (ret != 0)
        {
            AfxMessageBox("客户端密钥校验失败");
        }
        else
        {
            AfxMessageBox("客户端密钥校验成功");
        }
    
    }
    ViewClient.cpp

    5、图形客户端-删除控件对应函数

    问题抛出:如果添加按钮控件,未更改ID时,不小心双击了,就会生成OnBnClickedButton1()这样的回调函数,如何删除呢?以“IDD_DIALOG_CLIENT”界面添加按钮为例。

    解决:(1)切换到“类视图”,然后找到“CViewClient”类,然后右键打开“类向导”,弹出对话框,点击“方法”,选中需要删除的“OnBnClickedButton1”,在左侧点击“删除方法”:

    (2)在ViewClient.h中删除声明:

    (3)在ViewClient.cpp中删除消息映射和回调函数:

    6、图形客户端-密钥协商

    (1)双击按钮,设置密钥协商的回调函数void CViewClient::OnBnClickedButtonAgree()

    (2)测试:

    1)在Linux启动服务器(和Oracle数据库)

    注意:一定要启动服务器(和Oracle数据库)!

    2)在“VS”点击运行,弹出MyAdmin项目窗口,然后左侧点击“SecMngClient协商客户端”,点击“SecMngClient协商”,然后在右侧先点击“系统初始化”,再点击“密钥协商”

    报错:

    点击“继续”:

    点击“继续”,弹出“密钥协商ok”对话框:

    查看数据库的SECKYEINFO表:(数据插入成功)

    分析:由点击“继续”时项目定位的位置,知道这是内存释放错误的原因!

    7、图形客户端-密钥协商内存释放错误说明

    》内存释放:
        原则:谁开辟,谁释放。       
        创建库时,如有函数开辟了内存,必须提供对应的内存释放函数给用户。

    原keymngclientop.cpp中MngClient_Agree密钥协商函数的内存释放函数为:

    END:
        if (msgKey_Req_Data != NULL) 
            MsgMemFree((void **)&msgKey_Req_Data, 0);
        if (msgKey_Res_Data != NULL) 
            MsgMemFree((void **)&msgKey_Res_Data, 0);
        if (pStruct_Res != NULL) 
            MsgMemFree((void **)&pStruct_Res, iType);

    检查后,更改为:

    END:
        if (msgKey_Req_Data != NULL) 
            MsgMemFree((void **)&msgKey_Req_Data, 0);
            //sck_FreeMem((void**)&msgKey_Req_Data);
        if (msgKey_Res_Data != NULL) 
            //MsgMemFree((void **)&msgKey_Res_Data, 0);
            sck_FreeMem((void**)&msgKey_Res_Data);
        if (pStruct_Res != NULL) 
            MsgMemFree((void **)&pStruct_Res, iType);

    再次按照流程测试,成功了!

    可知:Linux释放内存程序检查的不够严格(虽然底层都是free实现),到wind的“VS”中检查比较严格,所以报错!

    8、总结
    》4大基础组件:
        1. 统一报文编码解码    libmessagereal.so .h ---> .dll .lib .h
        2. 统一通信组件socket    --- windows socket 通信        
        3. 共享内存        --- windows shm 机制
        4. 数据库访问    (客户端无需数据库)

    》物理组件集成:

        统一报文编解码组件: 
            messagereal.lib 、messagereal.dll 、 keymng_msg.h
            集成动态库到项目中。 属性 → 配置属性 → 连接器 → 输入 → 附加依赖项 → 编辑 → messagereal.lib
            messagereal.dll 放置到 .exe 所在目录位置。
            messagereal.lib 放置到 .cpp 所在目录位置。

        共享内存组件:
            myipc_shm.cpp 、myipc_shm.h
            集成源码到项目中。 属性 → 配置属性 → C/C++ → 常规 → SDL检查 → “否(/sdl-)”

        Socket通信组件:
            poolsocket.cpp 、poolsocket.h 、 socketlog.cpp 、 socketlog.h 、 socketutil.cpp 、 socketutil.h
            集成源码到项目中。

    -----将 Linux 业务代码移植到win下---------------------------------------------------
        添加与客户端相关的源码:
            keymng_shmop.c        → keymng_shmop.cpp
            keymngclient.c        是在Linux 下组织文字界面的,不需要。
            keymngclientop.c    → keymngclientop.cpp   
            keymnglog.c        → keymnglog.cpp       
            keymng_shmop.h
            keymngclientop.h
            keymnglog.h
            去除 cpp文件 #include 中 Linux 专用 头文件。
            添加    #define  _CRT_SECURE_NO_WARNINGS
                #include "stdafx.h"

        修改 源码对接平台差异错误:
            open(fileName,     O_WRONLY|O_CREAT|O_APPEND, 066)   →   (int) fopen(fileName,"w+")
            pNode = mapaddr + i*sizeof(NodeSHMInfo);   →    pNode = (NodeSHMInfo *)mapaddr + i*sizeof(NodeSHMInfo);
            ICLevelName    →    ICKeyMngLogName;

    ----- 整合图形客户端业务--------------------------------------------------------

        实现“系统初始化”Button 功能 :  ( initUpdate() )
            引入头文件:keymngclientop.h → ViewClient.cpp
            定义全局变量:MngClient_Info pCltInfo; → ViewClient.cpp  ---- 只读。
            调用:MngClient_InitInfo(&mngClientInfo); 初始化。    AfxMessage().显示错误信息。
            【注意】:修改 MngClient_InitInfo 中,服务器IP地址。
        实现“密钥协商”Button 功能:   
            调用:MngClient_Agree(&mngClientInfo); 协商密钥。AfxMessage().显示错误信息。
            【注意】:内存释放 MFC 中验证严格, ===== 把握:谁开辟,谁释放 原则。
            msgKey_Req_Data:是在报文编码过程中 使用 MsgEncode() 函数创建的内存。
                     应使用 MsgMemFree() 释放。 如:
                     MsgMemFree((void **)&msgKey_Req_Data, 0);
            msgKey_Res_Data:是在数据通信过程中 使用 sckClient_rev() 函数创建的内存。
                     应使用 sck_FreeMem() 释放。 如:
                     sck_FreeMem((void **)&msgKey_Res_Data);   

        实现“密钥校验”Button 功能:   
            调用:MngClient_Check(&mngClientInfo); 协商密钥。AfxMessage().显示错误信息。    

        实现“密钥注销”Button功能:   
            调用:MngClient_Revoke(&mngClientInfo); 协商密钥。AfxMessage().显示错误信息。   

    》内存释放:
        原则:谁开辟,谁释放。       
        创建库时,如有函数开辟了内存,必须提供对应的内存释放函数给用户。       
        int poolget(int **cache(传出));      int free(int *cache(传入));

    9、接口设计

    》项目框架再回顾与分析:

    所以,针对,app1和app2 需要提供两套接口(函数)!

    》接口(函数)设计分析:

    --------外联接口设计思想------------------------------------------------------
        .so/.dll 和 .h
        项目中外联接口主要有两个作用:    1. 读共享内存。    2. 加解密数据。

        函数接口:
            int DataEnc(char *clientid, char *serverid, unsigned char *indata, int indatalen, unsigned char *oudata, int *outdatalen);
            int DataDec(char *clientid, char * serverid, unsigned char *indata, int indatalen, unsigned char *outdata, int *outdatalen);
            int tag = 0 / 1; 加密, 解密。
            int DataEncAndDec(char *clientid, char *serverid, unsigned char *indata, int indatalen, unsigned char *outdata, int outdatalen);

        操作共享内存时, 需要使用到keyid。它可以以两种方式传入到函数接口中:
            1. 直接作为函数接口,传递到函数中。
                int DataEncAndDec(char *clientid, char *serverid, unsigned char *indata, int indatalen,
                          unsigned char *outdata, int outdatalen, int keyid, int maxnode);
            2. 接口读配置文件获取。
                配置文件应存放在: $(HOME)/etc/1.ini   e.g. KEYID=1111 、 MAXNODE=10
                这样,直接调接口效率会比较低。所以应封装初始化函数和结束函数给用户。
                int DataEncAndDec_init(char *filename);        //读配置文件,获取数据存入全局变量中。
                int DataEncAndDec(char *clientid, char *serverid, unsigned char *indata, int indatalen,
                          unsigned char *outdata, int outdatalen);
                int DataEncAndDec_finish();
        项目开发中,不同的用户需求,选用不同的接口封装方式,效率几近相同。没有孰优孰劣之分。

    10、文件加密原理

    =======对称加密:   加密秘钥和解密密钥一致==========================

        加密三要素:
            y = ax + b   明文、密文, 密钥, 算法。

       常见对称加密体系:
            AES    DES    3DES    SM3/n 
        分组加密原理:   
            采用分组加密的方式:对 不满足 8 字节部分,打padding。 但,从补丁明文恢复到原始明文时,有问题。无法区分原始明文和补丁明文。
            缺几补几。
            补丁长度 = 分组数据长度 - 数据长度 % 8   (缺8补8)    0-7   打补丁
                只对一整块数据,只做一次 padding 操作,        缺几补几。 

                大数据(大文件)要分块传输、存储。无论多大的数据,只对最后一个分组进行 padding 操作。在中间不能进行该操作。

                一般加密供应商给用户应提供两个API函数: 一个打padding的函数、一个不打padding的API函数。 

               大多数用户不了解加密过程,通常对其隐藏实现细节。只提供加密、解密接口。

    》加密原理分析图:

    》大文件 划分加密图:

    11、文件加密函数源码

    分析了DES源码(数据加密和解密)——cryptproj-文件加密项目(des.c、des.h、tmain.c)

    12、数字证书

    把DES源码封装,最后提供两套接口给用户:(appinterface/)

        //本地 加密
        ret = Appcryptapi(0, clientid, serverid, indata, indatalen, outdata, &outdatalen, cfg_shm_keyid, cfg_shm_maxnodenum);
        
        //本地 解密
        ret =  AppCryptApi(1, clientid, serverid, outdata, outdatalen, plain2, &plainlen2, cfg_shm_keyid, cfg_shm_maxnodenum);

     >appcryptapi.h

    #ifndef _APP_CRYPT_API_H_
    #define _APP_CRYPT_API_H_
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    
    
    //crypttag = 0   加密
    //crypttag = 1   解密
    int AppCryptApi(int crypttag, char *clientid, char *serverid, unsigned char *indata, int indatalen, 
        unsigned char *outdata, int *outdatalen, int cfg_shm_keyid, int cfg_shm_maxnodenum);
        
    #ifdef __cplusplus
    }
    #endif
    
    #endif
    appcryptapi.h

    >appcryptapitest.c

    #define _CRT_SECURE_NO_WARNINGS
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include "appcryptapi.h"
    
    int main(void)
    {
        //加密报文
        int                ret            = 0;
        int                crypttag    = 0;
        char            *clientid    = "1111";
        char            *serverid    = "0001";
    
        unsigned char    *indata = (char *)"aaaaaaaa";
        int                indatalen = strlen((char *)indata);
    
        unsigned char    outdata[4096];
        int                outdatalen = 4096;
    
        unsigned char    plain2[4096];
        int                plainlen2 = 4096;
    
        int cfg_shm_keyid = 0x0001;
        int cfg_shm_maxnodenum = 20;
    
        
        //本地 加密
        ret = Appcryptapi(0, clientid, serverid, indata, indatalen, outdata, &outdatalen, cfg_shm_keyid, cfg_shm_maxnodenum);
        if (ret != 0)
        {
            printf("func AppCryptApi() err:%d 
    ", ret);
            goto End;
        }
        
        //本地 解密
        ret =  AppCryptApi(1, clientid, serverid, outdata, outdatalen, plain2, &plainlen2, cfg_shm_keyid, cfg_shm_maxnodenum);
        if (ret != 0)
        {
            printf("func AppCryptApi() err:%d 
    ", ret);
            goto End;
        }
    
        if (plainlen2 != indatalen)
        {
            printf("解密以后明文大小不一样
    ");
            goto End;
        }
        else
        {
            printf(" 解密以后明文大小 一样
    ");
        }
        if ( memcmp(plain2,indata, indatalen ) != 0)
        {
            printf("校验解密后 明文不一样
    ");
            goto End;
        }
        else
        {
            printf("校验解密后 明文一样
    ");
        }
    
    }
    appcryptapitest.c

    然后结合 cryptproj-文件加密项目 进行编译

    新建目录appinterfaceso,然后进入该目录,新建incl目录(des.h、myipc_shm.h)、src目录(appcryptapi.c、des.c、myipc_shm.c)和makefile。

    >makefile

    # Makefile Module For Develop Team
    
    .SUFFIXES:
    .SUFFIXES:  .c .o
    
    WORKDIR=.
    INCLDIR=$(WORKDIR)/incl
    LIBDIR=$(HOME)/lib
    BINDIR=$(HOME)/bin
    
    CC=gcc
    
    INCLFLG= -I$(INCLDIR)
    LIBFLG = -L$(LIBDIR)
    CFLAG= -c -g $(INCLFLG) 
    LIBS = 
    
    VPATH = $(WORKDIR)/src
    
    OBJ1 = appcryptapi.o  des.o  myipc_shm.o
    
    
    libappinterface.so: $(OBJ1) 
        $(CC) -shared -fPIC $^  -o $@ 
        @cp $@ $(LIBDIR)
    
    .c.o:
        $(CC) -shared -fPIC $(CFLAG) $< -D_ITCAST_OS_LINUX
    
    #gcc       -shared -fPIC -c -g -I./incl   *.c--->*.o
        
    .PHONY : clean
    clean :
        rm  -f *.o
        rm  -f *.s
    makefile

    》补充:

    =======非对称加密=================================================

        特征:加密密钥 和 解密密钥,不一样。 密钥对(公钥、私钥)。   

        银行开户:
            1)提交身份证
            2)柜员 审核 ---> 人为管理
                1. 调用银行内部密钥生成系统,得到密钥对(公钥、私钥)。
                2. 将私钥灌入 KEY 中。(网银key、U盾)
                3. 将 公钥 + 个人身份信息 ---> 数字证书。     (包含“公钥”和“个人身份信息”两部分内容)

        数字证书:
            简单理解成“网络身份证”。解决了虚拟世界(网络世界)中,两端之间身份识别问题。

        示例:
            360 → 菜单 → “选项” → “高级设置” → “管理证书”
            MicroSoft edge → 菜单 → “使用 Internet Explorer 打开” → “工具” → “Internet 选项” → “内容”标签页 → “证书”
            可导出证书,选择.BER格式 或者 base64编码格式 (将DER编码后得到的可见字符格式)。

        查看证书:
            详细信息中,包含公钥和使用者相关身份信息。

        公钥的作用:
            1)验证身份                B → 验证 → A
                1. A 产生随机数 r1, 用私钥加密 r1 → r1S                        (签名)
                2. A 将 r1和r1S 给 B。 则B有了明文:r1 和 密文:r1S
                3. B 从公共网点上下载 A 的证书。 若 B 无法下载,A也可以将自己的证书一起给B。
                4. B 用 A的证书中的“公钥”,解密 密文:r1S → r2 。 校验 r1 和 r2 是否相等。         (验证签名)
                5. 若相等,则能确定,数据加密动作,是 A 完成的。
                签名,类似公司加盖公章。具有法律效力(电子签名法)。   
            2)数据加密:                C 、 D
                1. C 用 D 的公钥加密,将加密数据给D
                2. D 用自己的私钥解密。

    在学习安全传输平台项目总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

  • 相关阅读:
    系统操作日志设计代码实现
    SQL SERVER 存储过程复习
    IGrab信息采集系统流程图(初稿)
    收藏几段SQL语句和存储过程
    SQL Server联机丛书:存储过程及其创建
    使用dynamic来简化反射实现,并且提高了性能
    你必须知道的C#的25个基础概念(附演示)
    弹窗插件
    dede 搜索时出现“SphinxClient类找不到”解决
    开启includes模块运行shtml
  • 原文地址:https://www.cnblogs.com/Alliswell-WP/p/CPlusPlus_SecureTransmissionPlatform_Project11.html
Copyright © 2011-2022 走看看