简单UDP日志程序

来源:互联网 发布:php.ini 大文件大小 编辑:程序博客网 时间:2024/05/20 04:49
使用简单的宏Trace(...)就可以将字符串发送到指定的Udp服务端进行实时显示,Trace用法类似如printf传入可变参数,
它前两个参数是隐藏起来的分别是:文件名和行号,这样方便我们查找打印日志所在位置。

下面是完整客户端代码:

#include <stdio.h>#include <stdarg.h>#include <string>#include <Windows.h>#include <process.h>#include <time.h>#pragma comment(lib, "ws2_32.lib")#define Trace CTrace(__FILE__, __LINE__)class CUdpClient{public:    CUdpClient(const std::string &ip=std::string("127.0.0.1"), unsigned short port=5050)    {        init(ip, port);    }    void init(const std::string &ip, unsigned short port)    {        sock_ = INVALID_SOCKET;        memset(&sin_, 0, sizeof(sin_));        sin_.sin_family = AF_INET;        sin_.sin_addr.S_un.S_addr = inet_addr(ip.c_str());        sin_.sin_port = htons(port);        addrLen_ = sizeof(sin_);    }    ~CUdpClient()    {        closesocket(sock_);    }    int send(const std::string &str)    {        if (INVALID_SOCKET == sock_)        {            sock_ = socket(AF_INET, SOCK_DGRAM, 0);        }                if (INVALID_SOCKET != sock_)        {            return sendto(sock_, str.c_str(), str.size(), 0, (SOCKADDR*)&sin_, addrLen_);        }        return 0;    }private:    SOCKET sock_;    sockaddr_in sin_;    int addrLen_;};class CTrace{public:    CTrace(const char *path, int line)        : path_(path), line_(line)    {    }    void __cdecl operator()(const char *fmt, ...) const    {        va_list ptr;        va_start(ptr, fmt);        char buffer[4096] = {0};        std::string filename(path_);        int ipos = filename.find_last_of('\\');        filename = filename.substr(ipos+1, filename.size()-ipos+1);        int iret = sprintf_s(buffer, sizeof(buffer), "[%s, %d] ", filename.c_str(), line_);        if (-1 != iret)        {            vsnprintf_s(buffer+iret, sizeof(buffer)-iret-1, _TRUNCATE, fmt, ptr);            udp_.send(buffer);        }        va_end(ptr);    }private:    const char *path_;    const int line_;    static CUdpClient udp_;};CUdpClient CTrace::udp_;///////////////////////////////////////测试代码/////////////////////////////////////////////// 产生随机字符串std::string BuildRandString(int num){    static unsigned int s_add = 0;    std::string ret;    srand((unsigned int)time(NULL) + (s_add++));    for (int i=0; i<num; )    {        char buf[17] = {0};        _itoa_s(rand(), buf, 0x10);        ret += buf;        i += strlen(buf);    }    return ret.substr(0, num);}int _tmain(int argc, _TCHAR* argv[]){    WSADATA wsa;    int iret = WSAStartup(MAKEWORD(2, 2), &wsa);    if (0 != iret)    {        return 0;    }    int num = 0;    while (1)    {        char c = getchar(); // 每按下一个按键产生一条日志        std::string str = BuildRandString(100);        Trace("%d, %s", ++num, str.c_str()); // 用法    }    WSACleanup();    system("pause");    return 0;}
服务端使用WTL做了个简单的单文档list box形式的界面用来展现
WTL库安装下载地址:http://www.cnblogs.com/tujiaw/archive/2011/02/26/3059245.html
首先在对话框创建的时候初始化socket,创建接收数据线程

WSADATA wsa;        WSAStartup(MAKEWORD(2, 2), &wsa);        InitSocket();        m_threadHandle = (HANDLE)_beginthreadex(NULL, 0, RecvData, this, 0, NULL);     CloseHandle(m_threadHandle);
void InitSocket()    {        sockaddr_in sin;        memset(&sin, 0, sizeof(sin));        sin.sin_family = AF_INET;        sin.sin_addr.S_un.S_addr = htonl(INADDR_ANY);        sin.sin_port = htons(5050);        m_sock = socket(AF_INET, SOCK_DGRAM, 0);        if (INVALID_SOCKET != m_sock)        {            if (SOCKET_ERROR == bind(m_sock, (SOCKADDR*)&sin, sizeof(sin)))            {                closesocket(m_sock);            }        }    }
线程不断的接收数据并显示到界面上
unsigned int __stdcall RecvData(void* arg){    CMainFrame *p = (CMainFrame*)arg;    if (NULL == p)    {        return 0;    }    sockaddr_in clientAddr;    int clientLen = sizeof(clientAddr);    while(g_isRunning)    {        if (INVALID_SOCKET == p->m_sock)        {            break;        }        char buffer[4096] = {0};        if (recvfrom(p->m_sock, buffer, sizeof(buffer), 0, (sockaddr*)&clientAddr, &clientLen) > 0)        {            p->m_view.AddString(buffer);            p->m_view.PostMessageA(WM_VSCROLL, SB_BOTTOM);        }    }            return 0;}

双击单行可以将日志拷贝到剪切板上

LRESULT OnLButtonDClick(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)    {        char buffer[4096] = {0};        int curSel = GetCurSel();        int len = GetText(curSel, buffer);                BOOL bret = OpenClipboard();        EmptyClipboard();        HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, len + 1);        char *p = (char*)GlobalLock(hGlobal);        memset(p, 0, len+1);        memcpy(p, buffer, strlen(buffer));        bret = GlobalUnlock(hGlobal);        HANDLE hResult = SetClipboardData(CF_TEXT, hGlobal);        if (hResult)        {            memset(buffer, 0, sizeof(buffer));            sprintf_s(buffer, "拷贝数据到剪切板成功,长度:%d", len);            MessageBox(buffer);        }        CloseClipboard();        return 0;    }

源码是用vs2012编译的,只需要关注MainFrm.h文件就可以了,拷贝数据到剪切板代码在ShowTraceView.h中

下载地址:http://files.cnblogs.com/tujiaw/ShowTrace.rar