使用UDP(VC)发送接收日志
编者:李国帅
qq:9611153 微信lgs9611153
时间:2011/5/13
背景原因:
以前使用过此方法,好处是不会阻塞,当日志量比较大的时候能够快速反应。坏处就是udp发送大于最小传输单元的数据,或把不相关的数据连续密集发送,很可能造成数据错乱丢失。
发送:
//2011-9-29 10:51:01
//检查了一遍,发现mc中还是存在一些问题,log也不完善,可能丢数据,即便是进行了如下改造。
//udp不应该发送大于最小传输单元的数据,也不应该把不相关的数据连续密集发送,很可能造成数据错乱丢失。
#ifndef _M_LOG_H_
#define _M_LOG_H_
#include "stdio.h"
#pragma warning(disable : 4996)
#define LOG_EMERG 0 /* system is unusable */
#define LOG_ALERT 1 /* action must be taken immediately */
#define LOG_CRIT 2 /* critical conditions */
#define LOG_ERR 3 /* error conditions */
#define LOG_WARNING 4 /* warning conditions */
#define LOG_NOTICE 5 /* normal but significant condition */
#define LOG_INFO 6 /* informational */
#define LOG_DEBUG 7 /* debug-level messages */
#define LOG_ALREADY_INITED -1
#define LOG_ERROR -2
#define LOG_NOT_INITED -3
#define LOG_GETSIZE_ERROR -4
#define LOG_SEND_BUFFSIZE (1<<16)
#define NETWORK_MONITOR_PORT 3000
//#include "winsock2.h"//#include "winsock.h"
//#pragma comment(lib, "Ws2_32.lib")//wsock32.lib
class CNetLog
{
public:
CNetLog(int nPort)
{
m_nPort = nPort;
strcpy(m_nDebugNetIP,"127.0.0.1");
memset(&addrSendMinitor,0,sizeof(sockaddr_in));
addrSendMinitor.sin_family = AF_INET;
addrSendMinitor.sin_addr.s_addr = inet_addr(m_nDebugNetIP);// 从配置文件获取 IP
addrSendMinitor.sin_port = htons(m_nPort); //NETWORK_MONITOR_PORT//NETWORK_MONITOR_PORT+1
memset( &(addrSendMinitor.sin_zero),0,8);
nsockSend=socket(AF_INET,SOCK_DGRAM,0);// UDP
_ASSERT (nsockSend>0 && nsockSend < ((1<<16)-1));
_ASSERT(nsockSend!=INVALID_SOCKET);
memset(sendcontentbuf,0,LOG_SEND_BUFFSIZE);
}
~CNetLog()
{
if (nsockSend>0)
{
closesocket(nsockSend);
}
}
public:
void mlog(unsigned int level,const char *strHeader,const char *strInfo)
{
if (nsockSend<=0)return;
time_t now;
time(&now);
struct tm localt;
localtime_s(&localt,&now);
int ret= 0;
char * pInfo = NULL;
int nlen = (int)strlen(strInfo);
if (nlen<1200)
{
_snprintf_s(sendcontentbuf,LOG_SEND_BUFFSIZE,LOG_SEND_BUFFSIZE-1,"\n(%s:%d) (%04d/%02d/%02d %02d:%02d:%02d) %s",
strHeader,level,localt.tm_year+1900, localt.tm_mon+1,localt.tm_mday, localt.tm_hour, localt.tm_min, localt.tm_sec,strInfo);
sendcontentbuf[strlen(sendcontentbuf)] = 0;
pInfo = (char *)sendcontentbuf;
ret=sendto(nsockSend, pInfo, (int)strlen(pInfo)+1,0, (const sockaddr *)&addrSendMinitor, sizeof(addrSendMinitor));
//ATLASSERT(ret>0);
}
else
{
_snprintf_s(sendcontentbuf,LOG_SEND_BUFFSIZE,LOG_SEND_BUFFSIZE-1,"\n(%s:%d) (%04d/%02d/%02d %02d:%02d:%02d)",
strHeader,level,localt.tm_year+1900, localt.tm_mon+1,localt.tm_mday, localt.tm_hour, localt.tm_min, localt.tm_sec);
pInfo = (char *)sendcontentbuf;
nlen = (int)strlen(pInfo);
sendcontentbuf[nlen] = 0;
ret=sendto(nsockSend, pInfo,nlen+1 ,0, (const sockaddr *)&addrSendMinitor, sizeof(addrSendMinitor));
pInfo = (char *)strInfo;
nlen = (int)strlen(pInfo)+1;
int npacket = nlen/1000;
int nlen_per = 0;
if((nlen%1000)>0)npacket++;
for (int i=0;i<npacket;i++)
{
if(nlen>=1000)
{
nlen_per = 1000;
}
else
{
nlen_per = nlen;
}
strncpy(sendcontentbuf,pInfo,nlen_per);
sendcontentbuf[nlen_per] = 0;
int ret=sendto(nsockSend, sendcontentbuf,nlen_per+1 ,0, (const sockaddr *)&addrSendMinitor, sizeof(addrSendMinitor));
//ATLASSERT(ret>0);
if (ret < 0)OutputDebugString("mlog:sendto fail.\n");
nlen = nlen - nlen_per;
pInfo = pInfo+nlen_per;
}
}
}
private:
char m_nDebugNetIP[60];// host IP
int m_nPort;
SOCKET nsockSend;// global sock for debug log
struct sockaddr_in addrSendMinitor;
TCHAR sendcontentbuf[LOG_SEND_BUFFSIZE];
};
#endif
接收测试:
// Win32Test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <tchar.h>
#include <stdio.h>
#include <io.h>
#include <assert.h>
#include <stdlib.h>
#include <windows.h>
#include "winsock2.h"//#include "winsock.h"
#pragma comment(lib, "Ws2_32.lib")//wsock32.lib
#define VMS_BUFFSIZE 2048
int main(int argc, char* argv[])
{
WORD wVersionRequested = MAKEWORD(2,2);
WSADATA wsa;
int err = WSAStartup(wVersionRequested,&wsa);
if (err !=0)return -1;
int sock1=socket(AF_INET,SOCK_DGRAM,0);
if (INVALID_SOCKET == sock1)return -1;
char op = 1;
setsockopt(sock1,SOL_SOCKET,SO_REUSEADDR,&op,sizeof(int));
sockaddr_in addr;
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port =htons(3000);
addr.sin_addr.s_addr = ADDR_ANY;
bind(sock1,(sockaddr*)(&addr),sizeof(addr));
sockaddr_in from;
int fromlen = sizeof(sockaddr_in);
char* pMsg = (char *)malloc(VMS_BUFFSIZE);
int nMsgLen=0;
int i = 10000000;
while(i-->0)
{
struct timeval timeout;
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sock1, &readfds);
timeout.tv_sec = 0;
timeout.tv_usec = 1000;
int err = select(1, &readfds, NULL, NULL, &timeout);
if(err == 0){ //timeout
continue;
}
if(err < 0){
printf("SursvrCom select error %d", WSAGetLastError());
continue;
}
nMsgLen = recvfrom(sock1, (char *)pMsg, VMS_BUFFSIZE, 0, (struct sockaddr*)&from, &fromlen);
if(nMsgLen<=0){
continue;
}
printf("%s", (char *)pMsg);
}
free(pMsg);
//shutdown(sock1,SD_BOTH);
closesocket(sock1);
WSACleanup();
system( "PAUSE" );
return 0;
}