对于某些事件驱动行程序,往往存在大量的日志与消息的写入,如以单线程或者直接进行进程的写存会消耗进程大量的资源,不利于提高程效率。通多线程构建操作,将日写存交由线程处理,在日志写存量较大的程序中能显著的提高程序的运行效率。下面讨论的一种构将写日志的消息通过存取于队列之中,线程于队列中提消息进行写入。
线程相关知识不再这理作出相关讨论。百度上面有大量的相关知识。而我们首先要讨论的是Linux(centos 6.5)上面负责队列中相关消息收发函数。
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
msgsnd函数用于将到来的消息发送到队列中。其他各个形参对应的实际用途如下,
int msqid:为int msgget(key_t key, int msgflg);返回值 ,用于key创建的成功与否,在消息的收发之中,我们需要有一个固定的标识来标识不同的消息,如下存在3个消息队列。如无明确的标识,则会出现相关的混乱。
------ Message Queues --------
key msqid owner perms used-bytes messages
0x01050f47 262144 admin 666 0 0
0x01050f29 32769 admin 666 0 0
0x0104095c 65538 admin 600 3216 6
在实现msqid这前,我们需要定义实现key的赋值,可通过ftok实现。
key_t ftok(const char *pathname, int proj_id);
const void *msgp:发送至队列中相关消息缓存。
size_t msgsz:消息长度
int msgflg:相关标识
通过消息发送到队列中之后,我们则需要用msgrcv来进行读取队列中相关消息。
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
相关使用,于此不再作相关讨论。
在队列的结构体中,需要使用以下两个变量,long mtype 用于,如消息警告等级以及退出,可以通过定义mtpye来实现。
char mtext[]为发送消息缓存。
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
msgctl用于控制消息队列 中消息的移除。可参考相关百度
int msgctl(int msqid, int cmd, struct msqid_ds *buf);
上面介绍了队列相关处理方法,下面介绍相关原理。
代码:
msg.h
#include
#include
#include
#include
#include
#define LOG_EXIT 0x0500+10 //退出
#define LOG_WRITE 0x0500+20 //写入
#define LOG_ID 30
#define LINE 4096
#define MSG_FILE "/dev/null"
//use for the line need to think about it carefully
消息队列
struct msgbuf {
long mtype;
char mtext[2048];
};
msg.c 发送
#include "msg.h"
int msgsend(char *strSend,int type)
{
key_t key;
int nMsgid;
struct msgbuf data;
if((key = ftok(MSG_FILE, 1)) == -1){
perror("[error][ftok]ftok error");
return -1;
}
nMsgid = msgget(key+LOG_ID, 0666 | IPC_CREAT);
if(nMsgid == -1){
perror("[error][msgsend]msgget error");
return -1;
}
data.mtype = type ;
memset(data.mtext, 0, sizeof(data.mtext));
int nMaxSize = sizeof(data.mtext) - 1;
int nStrLen = strlen(strSend);
memcpy(data.mtext, strSend, nStrLen > nMaxSize ? nMaxSize : nStrLen);
if(msgsnd(nMsgid, (void*)&data, sizeof(data.mtext), IPC_NOWAIT) == -1){
perror("[error][msgsnd]msgsnd error");
return -1;
}
return 0;
}
write_log.h头文件
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define bool int
#define true 1
#define false 0
struct thread_info{
FILE* fd;
bool isopen;
pthread_t thread; //usr for the pthread as for pool of the pthread
char strPath[256];
int line;
// struct msgbuf data; //usr translated the data;
};
void print_log(const char* strFileName,int nLine,struct thread_info* pthread_data,const char *format,...);
void trace(const char* strFileName,int nLine, char* buf,struct thread_info* pthread_data);
bool write_log_open(char *strFileName,char * strMode,struct thread_info* pthread_data);
bool write_log(char* strContent,struct thread_info* pthread_data);
bool log_thread_stop(struct thread_info* pthread_data);
static void *log_create_thread(void* arg);
bool Log_write_string(const char *sFileName,int nFileLine,const char* strContent,char *end_string);
bool write_log_close(struct thread_info* pthread_data);
void pthread_init( struct thread_info* pthread_data);
write_log.c函数实现文件
#include "write_log.h"
#include "msg.h"
#define LOG_EXIT 0x0500+10 //退出
#define WRITE 0x0500+20 //写入
#define LOG_ID 30
#define BUF_LOG_LINE 4096
#define MSG_FILE "/dev/null"
//初始化掉结构体
void pthread_init( struct thread_info* pthread_data)
{
pthread_data->fd =NULL;
pthread_data->thread= NULL;
pthread_data->isopen = false;
memset(pthread_data->strPath,0,sizeof(pthread_data->strPath));
int line = 0;
}
bool write_log_close(struct thread_info* pthread_data)
{
printf("[fun] start to write_log_close...\n");
if(pthread_data->fd){
fflush(pthread_data->fd);
fclose(pthread_data->fd);
pthread_data->fd = NULL;
return true;
}
if(pthread_data->isopen == true){
pthread_data->isopen = false;
}
return false;
}
/**************************Log_write_string*********************/
/*用于在写入字符串中加入时间戳 *****/
/**************************Log_write_string*********************/
bool Log_write_string(const char *sFileName,int nFileLine,const char* strContent,char *end_string)
{
char str_title[LOG_TITLE+1] = {0};
char* strDest = NULL;
char* szTmpFileName = (char*)sFileName;
if(end_string == NULL){
end_string = (char*)malloc(2048);
}
strDest = (char*)malloc(strlen(strContent)+LOG_TITLE+200);
if(strDest == NULL || end_string == NULL){
return false;
}
int wMonth,wDay,wHour,wMinute,wSecond,wMilliseconds;
time_t timeval;
struct tm* tm_ptr;
struct timeval current;
gettimeofday(¤t, NULL);
timeval = current.tv_sec;
tm_ptr = localtime(&timeval);//or tm_ptr=gmtime(timeval);
wMonth = tm_ptr->tm_mon+1;
wDay = tm_ptr->tm_mday;
wHour = tm_ptr->tm_hour;
wMinute = tm_ptr->tm_min;
wSecond = tm_ptr->tm_sec;
wMilliseconds = current.tv_usec/1000;
sprintf(strDest,"%02d-%02d %02d:%02d:%02d.%03d(thread_id:0x%08X) %s,%s(%d)\n",
wMonth,wDay,wHour,
wMinute,wSecond,wMilliseconds,
(unsigned long)pthread_self(),strContent,
(char*)szTmpFileName,nFileLine);
strncpy(end_string,strDest,strlen(strDest));
//end_string = strDest;
// memcpy(end_string,strDest,sizeof(2048));
printf("[info][Log_write_string]will write to string is :%s\n",end_string);
return true;
}
/**************************log_create_thread*********************/
static void *log_create_thread(void *arg)
{
struct thread_info *thread_run_data = (struct thread_info *)arg;
printf("[fun][log_create_thread] log_create_thread start success,id is:0x%8x\n",pthread_self());
char* strBugLog = NULL;
char* eBugLog =(char *)malloc(2048);
strBugLog = (char *)malloc(2048);
if(strBugLog == NULL || eBugLog == NULL ){
sprintf(strBugLog,"[info]Log_thread(ThreadId:0x%08x) start.",
pthread_self());
write_log(strBugLog,thread_run_data);//start to the log
free(strBugLog);
strBugLog = NULL;
}
char* strFile = "netcat";
int msgid = -1;
int nFileLen = 0;
struct msgbuf data;
long msgtype = 0;
printf("[fun][log_create_thread] start success...\n");
key_t key = -1;
printf("[info][log_creat_thread] key value is :%d ,msgid value is:%d\n",key,msgid);
if((key = ftok(MSG_FILE, 1)) == -1) //系统建立IPC通讯(如消息队列、共享内存时)必须指定一个ID值
{
perror("[error][log_creat_thread] ftok error");
goto thread_log_exit;
}
msgid = msgget(key+LOG_ID, 0666 | IPC_CREAT);
if(msgid == -1){
perror("[error][log_creat_thread] msget error");
goto thread_log_exit;
}
printf("[info][log_write_thread] key value is :%d ,msgid value is:%d\n",key,msgid);
while(1){
printf("*************************************************\n");
system("ipcs -q");
printf("*************************************************\n");
int ret = msgrcv(msgid,&data,sizeof(data.mtext),msgtype,MSG_NOERROR);//MSGNOERROR
Log_write_string(thread_run_data->strPath,thread_run_data->line,data.mtext,strBugLog);
printf("*************************************************\n");
system("ipcs -q");
printf("*************************************************\n");
printf("strBugLog is %s\n",strBugLog);
if(ret == -1){
perror("[error][log_write_thread] msgrcv is failed");
goto thread_log_exit;
}
switch (data.mtype)
{
case WM_LOG_WRITE:
write_log(strBugLog,thread_run_data);
nFileLen += strlen(strBugLog);
if(nFileLen >= 1024*1024*50){
write_log_open(strFile,"w",thread_run_data);
nFileLen = 0;
}
break;
case WM_LOG_EXIT:
{
goto thread_log_exit;
}break;
default:
{
}break;
}
memset(strBugLog,0,sizeof(strBugLog));
}
thread_log_exit:
printf("[info][log_write_thread] error for thread_log_exit\n");
if(NULL != strBugLog){
free(strBugLog);
strBugLog = NULL;
}
if(eBugLog){
sprintf(eBugLog,"ThreadId:0x%08X) exit.",pthread_self());
msgctl(msgid,IPC_RMID,NULL);
write_log(eBugLog,thread_run_data);
free(eBugLog);
eBugLog = NULL;
write_log_close(thread_run_data->fd);
return 0;
}
}
/****************************log_thread_stop**********************/
/**关闭线程 ****/
/****************************log_thread_stop**********************/
bool log_thread_stop(struct thread_info *pthread_data){
printf("[fun][log_thread_stop]start success...\n");
char *strStop ="The thread will stoped";
char end_str[2048] ={0};
if(pthread_data->thread != NULL)
{
pthread_data->line +=1;
Log_write_string(pthread_data->strPath,pthread_data->line,strStop,end_str);
printf("[info][log_thread_stop] the pThread is send message to stop...\n");
msgsend(end_str,EXIT);
}
printf("[info][log_thread_stop] the pThread is not start...\n");
return true;
}
/****************************log_start_thread**********************/
bool log_start_thread(struct thread_info *pthread_data){
int s;
log_thread_stop(pthread_data);
s = pthread_create(&pthread_data->thread,NULL,&log_create_thread,pthread_data);
printf("[info][log_start_thread] pthread_data->fd :0x%8x\n",pthread_data->fd);
printf("[info][log_start_thread] pthread_data->thread :0x%8x\n",pthread_data->thread);
printf("[info][log_start_thread] pthread_data->isopen :%d\n", pthread_data->isopen);
printf("[info][log_start_thread] pthread_data->strPath :%s\n", pthread_data->strPath);
if(0 == s){
printf("[info] The thread start success..\n ");
return true;
}
return false;
}
/********************log_write*************************/
bool write_log(char* strContent,struct thread_info *pthread_data)
{
printf("[fun][write_log] write_log start success...%s\n",strContent);
assert(strContent && pthread_data);
if(pthread_data->isopen == true)
{
if(pthread_data->fd){
fwrite(strContent,sizeof(char),strlen(strContent),pthread_data->fd);
fflush(pthread_data->fd);
return true;
}
else
{
printf("[error][write_log]error for the open file\n");
return false;
}
}
printf("[error][write_log] not open the file for write\n");
return false;
}
/********************write_log_open**********************/
bool write_log_open(char *strFileName,char* strMode,struct thread_info *pthread_data)
{
time_t timeval;
struct tm* tm_ptr;
char strFileName_tmp[256] = {0};
int mMonth,mDay,mHour,mMinute,mSecond,mMilliseconds,mYear;
timeval = time(NULL);
tm_ptr = localtime(&timeval);
mMonth = tm_ptr->tm_mon;
mDay = tm_ptr->tm_mday;
mHour = tm_ptr->tm_hour;
mMinute = tm_ptr->tm_min;
mSecond = tm_ptr->tm_sec;
mYear = tm_ptr->tm_year;
sprintf(strFileName_tmp,"%s_%04d%02d%02d%02d%02d%02d.log",
strFileName,mYear,mMonth,mDay,mHour,mMinute,mSecond);
assert(strFileName != NULL && strMode !=NULL);
printf("[fun][write_log_open]strMod is :%s\n",strMode);
pthread_data->fd = fopen(strFileName_tmp,strMode);
if(NULL == pthread_data->fd){
printf("[error][write_log_open] open the %s file error\n",strFileName_tmp);
return false;
}
pthread_data->isopen = true;
printf("[fun] The write_log_open success...\n");
printf("[info] strFileName is :%s\n",strFileName_tmp);
return true;
}
/******************************* trace **********************/
/*e有无线程情况的判断及文件打开 */
/* */
/**************************************************************/
void trace(const char* strFileName,int nLine, char* buf,struct thread_info *pthread_data)
{
printf("[fun][trace] start success....\n");
char end_string[2047]={0};
if(pthread_data->thread == NULL)
{
char sFile[256] = {0};
char sPath[256] = {0};
char sLogPath[256] = {0};
int rslt = readlink("/proc/self/exe",sFile,256);
if(rslt > 0 || rslt <= 256){
sFile[rslt] = '\0';
}
char *pStr = strrchr(sFile,'/');
strncpy(sPath,sFile,pStr-sFile+1);
printf("[fun][trace]sPath is:%s\n",sPath);
char sFixedPath[256] = {0};
strcpy(sFixedPath,sPath);
strcat(sFixedPath,"log");
printf("[fun][trace]sFixedPath is:%s\n",sFixedPath);
DIR* dp = NULL;
dp = opendir(sFixedPath);
if(NULL == dp){
mkdir(sFixedPath,0x774);
strcat(sPath,"log/netcat_");
printf("[fun][trace]sPath is:%s\n",sPath);
}
else
{
strcat(sPath,"log/netcat_");
printf("[fun][trace]opendir success");
printf("[fun][trace]sPath is:%s\n",sPath);
}
strcat(sLogPath,sPath);
printf("Path:%s\n",sLogPath);
//先发消息进入队列,
msgsend(buf,WRITE);
system("ipcs -q");
//由结构体中的线程可知,线程未被创建
//此处为创建线程。先创建线程,
//先打开文件进行写操作
Log_write_string(pthread_data->strPath,pthread_data->line,buf,end_string);
write_log_open(sLogPath,"w+",pthread_data);
log_start_thread(pthread_data);
// pthread_join(pthread_data->thread,NULL);
}
Log_write_string(pthread_data->strPath,pthread_data->line,buf,end_string);
msgsend(end_string,WRITE);
// pthread_join(pthread_data->thread,NULL);
}
/*******************************trace fun**********************/
/*暂不加警告等级 */
/*c参数转换,后期等级加入 */
/**************************************************************/
void print_log(const char* strFileName,int nLine,struct thread_info* pthread_data,const char *format,...)
{
printf("[fun][print_log] start success....\n");
char buf[LINE];
va_list v1;
va_start(v1,format);
vsnprintf(buf,sizeof(buf),format,v1);
va_end(v1);
strncpy(pthread_data->strPath,strFileName,strlen(strFileName));
pthread_data->line = nLine;
trace(strFileName,nLine,buf,pthread_data);
}