使用简单的宏Trace(...)就可以将字符串发送到指定的Udp服务端进行实时显示,Trace用法类似如printf传入可变参数,
它前两个参数是隐藏起来的分别是:文件名和行号,这样方便我们查找打印日志所在位置。
WTL库安装下载地址:http://www.cnblogs.com/tujiaw/archive/2011/02/26/3059245.html
首先在对话框创建的时候初始化socket,创建接收数据线程
双击单行可以将日志拷贝到剪切板上
源码是用vs2012编译的,只需要关注MainFrm.h文件就可以了,拷贝数据到剪切板代码在ShowTraceView.h中
它前两个参数是隐藏起来的分别是:文件名和行号,这样方便我们查找打印日志所在位置。
下面是完整客户端代码:
#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中