/* 自定义打开、输出、关闭日志函数类型 */ typedef int funcOpenLog( LOG *g , char *log_pathfilename , void **open_handle ); typedef int funcWriteLog( LOG *g , void **open_handle , int log_level , char *buf , long len , long *writelen ); typedef int funcChangeTest( LOG *g , void **test_handle ); typedef int funcCloseLog( LOG *g , void **open_handle ); #define LOG_NO_OUTPUTFUNC NULL , NULL , NULL , NULL , NULL , NULL /* 设置输出类型 */ _WINDLL_FUNC int SetLogOutput( LOG *g , int output , char *log_pathfilename , funcOpenLog *pfuncOpenLogFirst , funcOpenLog *pfuncOpenLog , funcWriteLog *pfuncWriteLog , funcChangeTest *pfuncChangeTest , funcCloseLog *pfuncCloseLog , funcCloseLog *pfuncCloseLogFinally );
funcOpenLog funcOpenLog_ConnectToLogServer ; int funcOpenLog_ConnectToLogServer( LOG *g , char *log_pathfilename , void **open_handle ) { char *ptr = NULL ; char *ptr2 = NULL ; long log_pathfilename_len ; char ch_len ; char ip[ MAXLEN_IP + 1 ] ; long port ; long timeout ; int nret = 0 ; if( IsLogOpened(g) == 1 ) return 0; /* 申请日志打开环境句柄内存 */ (*open_handle) = (int*)malloc( sizeof(int) ) ; if( (*open_handle) == NULL ) { return -11; } /* 分析文件名和网络地址 */ ptr = strchr( log_pathfilename , '@' ) ; if( ptr == NULL ) return -21; log_pathfilename_len = ptr - log_pathfilename ; ch_len = (char)log_pathfilename_len ; ptr++; ptr2 = strchr( ptr , ':' ) ; memset( ip , 0x00 , sizeof(ip) ); strncpy( ip , ptr , ptr2 - ptr ); ptr2++; port = atol(ptr2) ; /* 创建客户端socket */ nret = TCPCreateClient( (int*)(*open_handle) ) ; if( nret ) return -31; /* 连接服务端socket */ nret = TCPConnectToServer( (int*)(*open_handle) , ip , port ) ; if( nret ) { CloseSocket( (int*)(*open_handle) ); return -32; } /* 发送文件名 */ timeout = 10 * 1000 ; nret = TCPSendData( *(int*)(*open_handle) , & ch_len , 1 , & timeout ) ; if( nret ) { CloseSocket( (int*)(*open_handle) ); return -33; } nret = TCPSendData( *(int*)(*open_handle) , log_pathfilename , log_pathfilename_len , & timeout ) ; if( nret ) { CloseSocket( (int*)(*open_handle) ); return -34; } SetOpenFlag(g,1); return 0; } funcWriteLog funcWriteLog_SendToLogServer ; int funcWriteLog_SendToLogServer( LOG *g , void **open_handle , int log_level , char *buf , long len , long *writelen ) { long timeout ; int nret = 0 ; if( IsLogOpened(g) == 0 ) return 0; /* 发送日志数据 */ timeout = 10 * 1000 ; (*writelen) = TCPSendData( *(int*)(*open_handle) , buf , len , & timeout ) ; if( (*writelen) ) { /* 如果发送失败,重连服务端,然后再发送,如果还失败,报错返回 */ funcCloseLog_DisconnectFromLogServer( g , open_handle ); nret = funcOpenLog_ConnectToLogServer( g , g->log_pathfilename , & (g->open_handle) ) ; if( nret ) return -41; timeout = 10 * 1000 ; (*writelen) = TCPSendData( *(int*)(*open_handle) , buf , len , & timeout ) ; if( (*writelen) <= 0 ) return -42; } return 0; } funcCloseLog funcCloseLog_DisconnectFromLogServer ; int funcCloseLog_DisconnectFromLogServer( LOG *g , void **open_handle ) { if( IsLogOpened(g) == 0 ) return 0; /* 断开socket连接 */ CloseSocket( (int*)(*open_handle) ); /* 释放日志打开环境内存 */ free( (*open_handle) ); SetOpenFlag(g,0); return 0; }
#include <stdio.h> #include "LOGSERVER.h" #define LOG_STYLES_TEST ( LOG_STYLE_DATETIME | LOG_STYLE_LOGLEVEL | LOG_STYLE_PID | LOG_STYLE_TID | LOG_STYLE_SOURCE | LOG_STYLE_FORMAT | LOG_STYLE_NEWLINE ) int test_iLOG3SERVER() { LOG *g = NULL ; char buffer[ 64 + 1 ] = "" ; long buflen = sizeof(buffer) - 1 ; int nret = 0 ; /* 创建日志句柄,带后缀'G'的函数还会自动设置到线程安全的全局缺省日志句柄 */ if( CreateLogHandleG() == NULL ) { printf( "CreateLogHandleG failed\n" ); return -1; } else { printf( "CreateLogHandleG ok\n" ); } /* 设置日志属性 */ nret = SetLogOutputG( LOG_OUTPUT_CALLBACK , "$ProgramFiles$/[email protected] :7878" , & funcOpenLog_ConnectToLogServer , NULL , & funcWriteLog_SendToLogServer , NULL , NULL , & funcCloseLog_DisconnectFromLogServer ) ; /* 设置输出类型时挂上那三个回调函数,实现自定义的连接远程日志服务器、输出日志数据到远程日志服务器、关闭通讯连接功能 */ if( nret ) { printf( "SetLogOutputG failed\n" ); return -1; } SetLogLevelG( LOG_LEVEL_INFO ); SetLogStylesG( LOG_STYLES_TEST , LOG_NO_STYLEFUNC ); /* 输出日志 */ DebugLogG( __FILE__ , __LINE__ , "hello DEBUG" ); InfoLogG( __FILE__ , __LINE__ , "hello INFO" ); WarnLogG( __FILE__ , __LINE__ , "hello WARN" ); ErrorLogG( __FILE__ , __LINE__ , "hello ERROR" ); FatalLogG( __FILE__ , __LINE__ , "hello FATAL" ); DebugHexLogG( __FILE__ , __LINE__ , buffer , buflen , "hello DEBUG" ); InfoHexLogG( __FILE__ , __LINE__ , buffer , buflen , "hello INFO" ); WarnHexLogG( __FILE__ , __LINE__ , buffer , buflen , "hello WARN" ); ErrorHexLogG( __FILE__ , __LINE__ , buffer , buflen , "hello ERROR" ); FatalHexLogG( __FILE__ , __LINE__ , buffer , buflen , "hello FATAL" ); /* 释放日志句柄 */ DestroyLogHandleG(); return 0; } int main() { /* windows上需要做初始化 */ SocketSystemInitial(); return -test_iLOG3SERVER(); }
#ifndef _H_SERVER_ #define _H_SERVER_ /* * iLOG3SERVER - iLOG3简单远程服务器 * author : calvin * email : * history : 2014-02-11 v1.0.0 创建 */ #include <stdio.h> #include "LibX.h" #include "StringX.h" #include "Socket.h" #include "SocketTCP.h" #include "LOGSERVER.h" #define IP_LOGSERVER "0" #define PORT_LOGSERVER 7878 #define MAXCNT_LOGCLIENT 100 #define CLIENTSTATUS_UNUSED 0 #define CLIENTSTATUS_LOGGING 2 #define RECV_BUFFER_SIZE 1024 #ifndef MAXLEN_FILENAME #define MAXLEN_FILENAME 256 #endif struct SocketAddressExp { char ip [ MAXLEN_IP + 1 ] ; long port ; } ; struct LogClientAccept { char status ; /* 连接状态 */ int clisock ; /* 已接受socket描述字 */ SOCKADDR cliaddr ; /* 已接受socket地址信息 */ struct SocketAddressExp cliaddr_exp ; /* 已接受socket地址信息(转换为易读格式) */ char log_pathfilename[ MAXLEN_FILENAME + 1 ] ; FILE *fp ; } ; struct LogServerEnv { int lsnsock ; /* 侦听socket描述字 */ SOCKADDR lsnaddr ; /* 侦听socket地址信息 */ struct LogClientAccept client[ MAXCNT_LOGCLIENT ] ; /* 客户端socket环境单元集 */ } ; int LogServer( char *server_ip , long server_port ); int SendSocketData( struct LogServerEnv *penv , struct LogClientAccept *pselclient ); int ProcessSocketData( struct LogServerEnv *penv , struct LogClientAccept *pselclient ); int ReceiveSocketData( struct LogServerEnv *penv , struct LogClientAccept *pselclient ); #endif [/code] server.c [code=c] static int AcceptClientSocket( struct LogServerEnv *penv ) { int clisock ; SOCKADDR cliaddr ; struct SocketAddressExp cliaddr_exp ; long timeout ; char ch ; long ch_len ; char log_pathfilename[ MAXLEN_FILENAME + 1 ] ; long log_pathfilename_len ; char env_key[ MAXLEN_FILENAME + 1 ] ; long env_key_len ; char *env_val = NULL ; long env_val_len ; char *p1 = NULL , *p2 = NULL ; FILE *fp = NULL ; int i ; struct LogClientAccept *pclient = NULL ; int nret ; /* 接受新socket连接 */ nret = TCPAcceptFromClient( & (penv->lsnsock) , & clisock , & cliaddr ) ; if( nret ) { printf( "TCPAcceptFromClient failed[%d]errno[%d]\n" , nret , errno ); return 0; } else { memset( & cliaddr_exp , 0x00 , sizeof(cliaddr_exp.ip) ); GetSocketAddressIP( & cliaddr , cliaddr_exp.ip ); GetSocketAddressPort( & cliaddr , & (cliaddr_exp.port) ); printf( "TCPAcceptFromClient ok , ip[%s]port[%ld]\n" , cliaddr_exp.ip , cliaddr_exp.port ); } /* 接收文件名长度 */ timeout = 10 * 1000 ; ch = 0 ; ch_len = 1 ; nret = TCPReceiveData( clisock , & ch , & ch_len , & timeout ) ; if( nret ) { printf( "TCPReceiveData failed[%d]errno[%d]\n" , nret , errno ); CloseSocket( & clisock ); return 0; } memset( log_pathfilename , 0x00 , sizeof(log_pathfilename) ); log_pathfilename_len = (long)ch ; nret = TCPReceiveData( clisock , log_pathfilename , & log_pathfilename_len , & timeout ) ; if( nret ) { printf( "TCPReceiveData failed[%d]errno[%d]\n" , nret , errno ); CloseSocket( & clisock ); return 0; } p1 = strchr( log_pathfilename , '$' ); while( p1 ) { /* 展开环境变量 */ p2 = strchr( p1 + 1 , '$' ) ; if( p2 == NULL ) return LOG_RETURN_ERROR_PARAMETER; memset( env_key , 0x00 , sizeof(env_key) ); env_key_len = p2 - p1 + 1 ; strncpy( env_key , p1 + 1 , env_key_len - 2 ); env_val = getenv( env_key ) ; if( env_val == NULL ) { printf( "environment [%s] not found\n" , env_key ); CloseSocket( & clisock ); return 0; } env_val_len = strlen(env_val) ; if( log_pathfilename_len + ( env_val_len - env_key_len ) > sizeof(log_pathfilename)-1 ) { printf( "filename overflow\n" ); CloseSocket( & clisock ); return 0; } memmove( p2+1 + ( env_val_len - env_key_len ) , p2+1 , strlen(p2+1) + 1 ); memcpy( p1 , env_val , env_val_len ); log_pathfilename_len += env_val_len - env_key_len ; p1 = strchr( p1 + ( env_val_len - env_key_len ) , '$' ); } fp = fopen( log_pathfilename , "a" ) ; if( fp == NULL ) { printf( "fopen failed errno[%d]\n" , nret , errno ); CloseSocket( & clisock ); return 0; } /* 查询未使用客户端socket环境单元 */ for( i = 0 , pclient = & (penv->client[0]) ; i < MAXCNT_LOGCLIENT ; i++ , pclient++ ) { if( pclient->status == CLIENTSTATUS_UNUSED ) { break; } } if( i >= MAXCNT_LOGCLIENT ) { printf( "太多的客户端\n" ); CloseSocket( & clisock ); return 0; } /* 填充客户端socket环境单元 */ pclient->clisock = clisock ; memcpy( & (pclient->cliaddr) , & cliaddr , sizeof(SOCKADDR) ); memcpy( & (pclient->cliaddr_exp) , & cliaddr_exp , sizeof(struct SocketAddressExp) ); strcpy( pclient->log_pathfilename , log_pathfilename ); pclient->fp = fp ; pclient->status = CLIENTSTATUS_LOGGING ; return 0; } int ReceiveSocketData( struct LogServerEnv *penv , struct LogClientAccept *pselclient ) { char recv_buffer[ RECV_BUFFER_SIZE + 1 ] ; int recv_len ; int nret = 0 ; /* 接收通讯数据到临时接收缓冲区 */ memset( recv_buffer , 0x00 , sizeof(recv_buffer) ); recv_len = sizeof(recv_buffer)-1 ; recv_len = recv( pselclient->clisock , recv_buffer , recv_len , 0 ) ; if( recv_len == 0 ) { printf( "socket closed by remote[%s:%ld]\n" , pselclient->cliaddr_exp.ip , pselclient->cliaddr_exp.port ); CloseSocket( & (pselclient->clisock) ); fclose( pselclient->fp ); pselclient->status = CLIENTSTATUS_UNUSED ; return 0; } else if( recv_len < 0 ) { printf( "read socket failed from remote[%s:%ld] , errno[%d]\n" , pselclient->cliaddr_exp.ip , pselclient->cliaddr_exp.port , errno ); CloseSocket( & (pselclient->clisock) ); fclose( pselclient->fp ); pselclient->status = CLIENTSTATUS_UNUSED ; return 0; } fprintf( pselclient->fp , "%s" , recv_buffer ); return 0; } int LogServer( char *server_ip , long server_port ) { struct LogServerEnv env , *penv = & env ; int selsocks[ 1 + MAXCNT_LOGCLIENT ] ; struct LogClientAccept *pselclient[ 1 + MAXCNT_LOGCLIENT ] ; int selsocks_count ; struct LogClientAccept *pclient = NULL ; int i ; int selsock_index ; int nret = 0 ; /* 初始化聊天环境 */ memset( penv , 0x00 , sizeof(struct LogServerEnv) ); /* 创建服务端侦听socket */ nret = TCPCreateServer( & (penv->lsnsock) , & (penv->lsnaddr) , server_ip , server_port ) ; if( nret ) { printf( "TCPCreateServer failed[%d]errno[%d]\n" , nret , errno ); return -1; } else { printf( "TCPCreateServer ok , ip[%s]port[%ld]\n" , server_ip , server_port ); } /* 主循环 */ while(1) { /* 准备socket描述字集合 */ selsocks[0] = penv->lsnsock ; selsocks_count = 1 ; for( i = 0 , pclient = & (penv->client[0]) ; i < MAXCNT_LOGCLIENT ; i++ , pclient++ ) { if( pclient->status != CLIENTSTATUS_UNUSED ) { selsocks[selsocks_count] = pclient->clisock ; pselclient[selsocks_count] = pclient ; selsocks_count++; } } /* 等待socket描述字事件 */ selsock_index = SelectSocket( selsocks , selsocks_count , SELECTSOCKET_READ , NULL ) ; if( selsock_index < 0 ) { printf( "SelectSocket failed[%d]errno[%d]\n" , selsock_index , errno ); return -1; } /* 处理socket描述字事件 */ if( selsock_index == 0 ) { /* 接受新socket连接 */ nret = AcceptClientSocket( penv ) ; if( nret ) { printf( "AcceptClientSocket failed[%d]errno[%d]\n" , nret , errno ); return -1; } } else { /* 接收已连接socket数据 */ nret = ReceiveSocketData( penv , pselclient[selsock_index] ) ; if( nret ) { printf( "ReceiveSocketData failed[%d]errno[%d]\n" , nret , errno ); return -1; } } } /* 关闭所有已连接socket */ for( i = 0 , pclient = & (penv->client[0]) ; i < MAXCNT_LOGCLIENT ; i++ , pclient++ ) { if( pclient->status != CLIENTSTATUS_UNUSED ) { CloseSocket( & (pclient->clisock) ); fclose( pclient->fp ); } } /* 关闭服务端侦听socket */ CloseSocket( & (penv->lsnsock) ); return 0; } static void usage( char *i ) { printf( "USAGE : %s server_ip server_port\n" , i ); return; } int main( int argc , char *argv[] ) { int nret = 0 ; if( argc != 1 + 2 ) { usage( argv[0] ); exit(7); } /* 初始化网络通讯环境(windows上需要) */ SocketSystemInitial(); /* 启动聊天服务器 */ nret = -LogServer( argv[1] , atol(argv[2]) ) ; /* 销毁网络通讯环境 */ SocketSystemDestroy(); return nret; }