因项目需要,写了个基于邮槽技术的log server,运行起来相当的不错,摆脱了fwrite等直接写log方法的不好的地方,分享如下。
#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#include <iostream>
#define MAILSLOT_LOG_SERVER_NAME TEXT("\\\\.\\mailslot\\mailslot_log_server"
static HANDLE hSlot = INVALID_HANDLE_VALUE;
static DWORD g_ulLogsCount = 0;
BOOL ReadSlot()
{
DWORD cbMessage, cMessage, cbRead;
BOOL fResult;
LPTSTR lpszBuffer;
TCHAR achID[80];
DWORD cAllMessages;
HANDLE hEvent;
OVERLAPPED ov;
cbMessage = cMessage = cbRead = 0;
fResult = GetMailslotInfo( hSlot, // mailslot handle
(LPDWORD) NULL, // no maximum message size
&cbMessage, // size of next message
&cMessage, // number of messages
(LPDWORD) NULL); // no read time-out
if (!fResult)
{
printf("GetMailslotInfo failed with %d.\n", GetLastError());
return FALSE;
}
if (cbMessage == MAILSLOT_NO_MESSAGE)
{
//printf("Waiting for a message...\n");
return TRUE;
}
cAllMessages = cMessage;
hEvent = CreateEvent(NULL, FALSE, FALSE, TEXT("EemsSlotEvent"));
if( NULL == hEvent ) {
printf("Create overlap event failed !!! \n");
return FALSE;
}
ov.Offset = 0;
ov.OffsetHigh = 0;
ov.hEvent = hEvent;
while (cMessage != 0) // retrieve all messages
{
// Create a message-number string.
#if(1)
if (g_ulLogsCount >= 0x10000) {
StringCchPrintf((LPTSTR) achID, 80, TEXT("%lx "), g_ulLogsCount + 1);
} else {
StringCchPrintf((LPTSTR) achID, 80, TEXT("%04lx "), g_ulLogsCount + 1);
}
#else
StringCchPrintf((LPTSTR) achID,
80,
TEXT("[#%d.%d] "),
cAllMessages - cMessage + 1,
cAllMessages);
#endif
// Allocate memory for the message.
int iDestLength = lstrlen((LPTSTR) achID) * sizeof(TCHAR) + cbMessage;
lpszBuffer = (LPTSTR) GlobalAlloc(GPTR, iDestLength + 1);
if( NULL == lpszBuffer )
return FALSE;
lpszBuffer[0] = '\0';
StringCbCopy(lpszBuffer, iDestLength, achID);
fResult = ReadFile(hSlot,
lpszBuffer + iDestLength - cbMessage,
cbMessage,
&cbRead,
&ov);
if (!fResult)
{
printf("ReadFile failed with %d.\n", GetLastError());
CloseHandle(hEvent);
GlobalFree((HGLOBAL) lpszBuffer);
return FALSE;
}
// Concatenate the message and the message-number string.
//StringCbCat(lpszBuffer,
// lstrlen((LPTSTR) achID)*sizeof(TCHAR)+cbMessage,
// (LPTSTR) achID);
// Display the message.
_tprintf(TEXT("%s\n"), lpszBuffer);
g_ulLogsCount++;
GlobalFree((HGLOBAL) lpszBuffer);
fResult = GetMailslotInfo(hSlot, // mailslot handle
(LPDWORD) NULL, // no maximum message size
&cbMessage, // size of next message
&cMessage, // number of messages
(LPDWORD) NULL); // no read time-out
if (!fResult)
{
CloseHandle(hEvent);
printf("GetMailslotInfo failed (%d)\n", GetLastError());
return FALSE;
}
}
CloseHandle(hEvent);
return TRUE;
}
BOOL WINAPI MakeSlot(LPTSTR lpszSlotName)
{
hSlot = CreateMailslot(lpszSlotName,
0, // no maximum message size
MAILSLOT_WAIT_FOREVER, // no time-out for operations
(LPSECURITY_ATTRIBUTES) NULL); // default security
if (hSlot == INVALID_HANDLE_VALUE)
{
printf("CreateMailslot failed with %d\n", GetLastError());
return FALSE;
}
else
{
printf("Mailslot created successfully.\n");
}
return TRUE;
}
//线程处理函数
DWORD WINAPI RecvThreadProc(LPVOID lpParam)
{
HANDLE hRecvMailSlot = (HANDLE)lpParam;
DWORD dwWaitResult;
while (INVALID_HANDLE_VALUE != hRecvMailSlot) {
dwWaitResult = WaitForSingleObject(hRecvMailSlot, INFINITE);
try {
switch (dwWaitResult)
{
case WAIT_OBJECT_0:
ReadSlot();
break;
case WAIT_ABANDONED:
CloseHandle(hRecvMailSlot);
hRecvMailSlot = INVALID_HANDLE_VALUE;
break;
}
}
catch(...)
{
// Handle error.
CloseHandle(hRecvMailSlot);
hRecvMailSlot = INVALID_HANDLE_VALUE;
}
Sleep(50);
}
if (INVALID_HANDLE_VALUE != hRecvMailSlot) {
//关闭邮槽
CloseHandle(hRecvMailSlot);
}
return NULL;
}
//
void SetColor(unsigned short ForeColor=4,unsigned short BackGroundColor=0) //给参数默认值,使它可以接受0/1/2个参数
{
HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE); //本例以输出为例
SetConsoleTextAttribute(hCon, ForeColor | BackGroundColor);
};
int _tmain(int argc, _TCHAR* argv[])
{
SetConsoleTitle("Mailslots Log Server Running ...");
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
// Get handles to STDIN and STDOUT.
HANDLE hStdout;
hStdout = GetStdHandle(STD_OUTPUT_HANDLE); // Save the current text colors.
if (GetConsoleScreenBufferInfo(hStdout, &csbiInfo))
{
WORD wOldColorAttrs = csbiInfo.wAttributes;
// Set the text attributes to draw red text on black background.
if (SetConsoleTextAttribute(hStdout, FOREGROUND_GREEN | FOREGROUND_INTENSITY))
{
std::cout << "-----------------------------------------------------------------------" << std::endl;
SetConsoleTextAttribute(hStdout, wOldColorAttrs);
}
}
if (MakeSlot(MAILSLOT_LOG_SERVER_NAME)) {
HANDLE hThread = CreateThread(NULL, 0, RecvThreadProc, hSlot, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
}
return 0;
}
在客户端,CreateFile(MAILSLOT_LOG_SERVER_NAME,...) 然后再WriteFile就可以了,非常地简单
如果在dll中实现客户端,并实现Singleton模式,可以实现在各个DLL和exe访问同一个客户端,这样,讨厌的在各个DLL插件中不能输出log的情况一并解决。如果要实现log分级,需要修改上述的代码,如果不嫌麻烦,可以将log分级按不同颜色输出,帅呆了!