安全传输平台项目——客户端代码移植-项目模块总结
在学习安全传输平台项目总结了笔记,并分享出来。有问题请及时联系博主: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
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.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("共享内存不存在, 创建共享内存\n"); 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; }
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.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\n", 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 \n", 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 \n", 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 \n", hdl->valid, hdl->nvalid, hdl->bounds); return ret; }
>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.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]\n", 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 ; }
>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.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\n"); 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\n"); // 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\n"); ret = 0; } else { //printf("4444444444444444:%d\n", 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\n", 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\n", 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\n ", 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\n ", 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 \n", 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 \n", 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 \n", 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 \n", 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 \n", ret); Socket_Log(__FILE__, __LINE__,SocketLevel[4], ret,"func readn() err, peer closed"); return ret; } *out = tmpBuf; *outlen = n; tmpBuf[n] = '\0'; //多分配一个字节内容,兼容可见字符串 字符串的真实长度仍然为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 \n", 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] = '\0'; return 0; } //服务器端 关闭连接 int sckServer_close(int connfd) { //close(connfd); closesocket(connfd); return 0; } //服务器端环境释放 int sckServer_destroy() { return 0; }
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.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("客户端密钥校验成功"); } }
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
>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 \n", 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 \n", ret); goto End; } if (plainlen2 != indatalen) { printf("解密以后明文大小不一样\n"); goto End; } else { printf(" 解密以后明文大小 一样\n"); } if ( memcmp(plain2,indata, indatalen ) != 0) { printf("校验解密后 明文不一样\n"); goto End; } else { printf("校验解密后 明文一样\n"); } }
然后结合 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
》补充:
=======非对称加密=================================================
特征:加密密钥 和 解密密钥,不一样。 密钥对(公钥、私钥)。
银行开户:
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,转载请注明出处。
posted on 2020-08-02 17:45 Alliswell_WP 阅读(611) 评论(1) 编辑 收藏 举报