⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tracer.cpp

📁 网络技术随着科学技术的发展越发先进与重要。
💻 CPP
字号:
// Tracer.cpp: implementation of the CTracer class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "TraceRoute.h"
#include "Tracer.h"
#include "TraceRouteDlg.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CTracer::CTracer()
{
	m_nSeq=1;
	icmpData=NULL;
	icmpRcvBuf=NULL;
    m_hSocket=INVALID_SOCKET;

	//初始化socket
    WSADATA wsaData;
    if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
    {
	    AfxMessageBox("WSAStartup()出错!");
    }
  
}

CTracer::~CTracer()
{
	//关闭Socket
	if (m_hSocket!=NULL)
		closesocket(m_hSocket);
	WSACleanup();
}

//填充ICMP报文首部

void CTracer::FillICMPData(char* icmpData,int size)
{
	memset(icmpData,0,size);
	ICMPHEADER* icmpHeader=NULL;
	icmpHeader=(ICMPHEADER*)icmpData;

	icmpHeader->i_type =ICMP_ECHO;
	icmpHeader->i_code =0;
	icmpHeader->i_id =(USHORT)GetCurrentProcessId();
	icmpHeader->i_seq =m_nSeq++; 
	//GetTickCount返回从0点到现在的毫秒数,作时间戳
	icmpHeader->timestamp=GetTickCount();
	char* datapart=icmpData+sizeof(ICMPHEADER);
    memset(datapart,'*',size-sizeof(ICMPHEADER));
	//填充校验和
    icmpHeader->i_cksum =CheckSum(icmpData,size);
}

//由字符串转化为地址

BOOL CTracer::FillAddress(char *addrDest)
{
	memset(&m_addrDest,0,sizeof(m_addrDest));
	m_addrDest.sin_family =AF_INET;
	if(inet_addr(addrDest)==INADDR_NONE)
	{
		//输入的地址为计算机名字
		HOSTENT* hp=NULL;
		hp=gethostbyname(addrDest);
		if(hp)
		{
		    memcpy(&(m_addrDest.sin_addr),hp->h_addr,hp->h_length);
			m_addrDest.sin_family =hp->h_addrtype ;
		}
		else
		{
			AfxMessageBox("获取地址失败!");
			return FALSE;
		}
	}
	else
	{
		m_addrDest.sin_addr.s_addr=inet_addr(addrDest);
	}
	return TRUE;
}

void CTracer::Trace(char *destAddress)
{
	 int size=DEF_PACKET_SIZE+sizeof(ICMPHEADER);
	 //转换地址
     if (!FillAddress(destAddress)) return ;

	 //分配必要的内存空间
	 icmpData=(char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);
	 icmpRcvBuf=(char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,MAX_PACKET);
	 if(!icmpData||!icmpRcvBuf)
	 {
		 AfxMessageBox("分配内存空间失败!");
		 TerminateProcess(GetCurrentProcess(),-1);
	 }
	 memset(icmpData,0,MAX_PACKET);
	 memset(icmpRcvBuf,0,MAX_PACKET);
	 


     //初始化套接字
	 m_hSocket=WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL,0,WSA_FLAG_OVERLAPPED);
	 if(m_hSocket==INVALID_SOCKET)
	 {   
		 AfxMessageBox("套接字初始化失败!");
		 TerminateProcess(GetCurrentProcess(),-1);
	 }
	
	 //设置超时选项
	 int nTimeOut=1000;
	 int result;
	 result=setsockopt(m_hSocket,SOL_SOCKET,SO_RCVTIMEO,(char*)&nTimeOut,sizeof(nTimeOut));
	 if(result==SOCKET_ERROR)
	 { 
		 AfxMessageBox("设置接收超时选项失败!");
		 TerminateProcess(GetCurrentProcess(),-1);
	 }
	 result=setsockopt(m_hSocket,SOL_SOCKET,SO_SNDTIMEO,(char*)&nTimeOut,sizeof(nTimeOut));
	 if(result==SOCKET_ERROR)
	 {
		 AfxMessageBox("设置发送超时选项失败!");
		 TerminateProcess(GetCurrentProcess(),-1);
	 }
	 //设置路由不查询路由表选项
	 BOOL bDontRoute=TRUE;
	 result=setsockopt(m_hSocket,SOL_SOCKET,SO_DONTROUTE,(char*)&bDontRoute,sizeof(BOOL));
	 if(result==SOCKET_ERROR)
	 {
		 AfxMessageBox("设置不查询路由表选项失败!");
		 TerminateProcess(GetCurrentProcess(),-1);
	 }

	 for(int ttl=1;ttl<MAX_NOTES;ttl++)
	 {
		 //设定数据报的寿命
		 SetTTL(m_hSocket,ttl);
		 //发送数据报
		 if(SendData(icmpData,size)) continue; 
		 //接收数据报
		 if(RecvData(icmpRcvBuf,&result)) continue; 
		 //处理接收到的数据报
		 if (DecodeICMP(icmpRcvBuf,result,ttl)) break;
	 }
	 
	HeapFree(GetProcessHeap(), 0, icmpData);
    HeapFree(GetProcessHeap(), 0, icmpRcvBuf);

}

//设置数据报的寿命
BOOL CTracer::SetTTL(SOCKET hSocket, int ttl)
{
	int result;
	result=setsockopt(hSocket,IPPROTO_IP,IP_TTL,(LPSTR)&ttl,sizeof(ttl));
	if(result==SOCKET_ERROR)
	{
		AfxMessageBox("设置数据报寿命失败!");
		TerminateProcess(GetCurrentProcess(),-1);
	}
	return TRUE;
}

//校验和算法
USHORT CTracer::CheckSum(char* pBuffer,int size)
{   

	USHORT* buffer=(USHORT*)pBuffer;
	unsigned long cksum=0;
    while(size > 1) 
    {
        cksum += *buffer++;
        size -= sizeof(USHORT);
    }
    if(size )
        cksum += *(UCHAR*)buffer;
    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >> 16);
    return (USHORT)(~cksum);
}

//处理接收到的数据报
BOOL CTracer::DecodeICMP(char* pBuffer,int bytes,int ttl)
{
    IPHEADER       *ipHeader=NULL;
    ICMPHEADER     *icmpHeader=NULL;
    unsigned short  ipHeaderLen;
    HOSTENT *ph=NULL;
    in_addr inaddr=m_addrFrom.sin_addr;

    ipHeader=(IPHEADER*)pBuffer;
	ipHeaderLen=20;

    if (bytes<ipHeaderLen+ICMP_MIN) 
		AfxMessageBox("接收数据报长度不正确!");
	
	icmpHeader=(ICMPHEADER*)(pBuffer+20);
    
    switch (icmpHeader->i_type)
    {
		//目的站点的返回
        case ICMP_ECHOREPLY:     
            ph=gethostbyaddr((const char *)&inaddr,AF_INET, sizeof(in_addr));
            if (ph != NULL)
			{
				CString report;
				report.Format("%2d  %s (%s)",ttl,ph->h_name,inet_ntoa(inaddr));
				((CTraceRouteDlg*)m_pWnd)->InfoAdd(report);
			}
			return TRUE;
            break;
		//中途路由器的返回
        case ICMP_TIMEOUT:     
            {
				CString report;
				report.Format("%2d  %s", ttl, inet_ntoa(inaddr));
				((CTraceRouteDlg*)m_pWnd)->InfoAdd(report);
				return FALSE;
				break;
			}
		//错误 主机不可达
        case ICMP_DESTUNREACH:  
            {
				CString report;
				report.Format("%2d  %s   主机不可达",ttl,inet_ntoa(inaddr));
				((CTraceRouteDlg*)m_pWnd)->InfoAdd(report);
				return TRUE;
				break;
			}
		//收到一个不是回应的报文
        default:
			{
				CString report;
				report.Format("非回应报文");
				((CTraceRouteDlg*)m_pWnd)->InfoAdd(report);
				return TRUE;
			}
           
    }
    return FALSE;
}

//发送数据报
BOOL CTracer::SendData(char* icmpData,int size)
{
	//填充ICMP报头
    FillICMPData(icmpData,size);

	//发送数据报
	int result;
	result=sendto(m_hSocket,icmpData,size,0,(SOCKADDR*)&m_addrDest,sizeof(m_addrDest));
		 
	if(result==SOCKET_ERROR)
	{
		if(WSAGetLastError()==WSAETIMEDOUT)
		{
			((CTraceRouteDlg*)m_pWnd)->InfoAdd ("发送超时");
			return TRUE;
		}
		AfxMessageBox("发送报文失败!");
		TerminateProcess(GetCurrentProcess(),-1);
	}
	return FALSE;
}

BOOL CTracer::RecvData(char* icmpRcvBuf,int* presult)
{
	static int count=0;
	//总共6次出现接收超时,判断存在连接问题。
	if(count>5)            
	{
		AfxMessageBox("连接存在问题!");
		TerminateProcess(GetCurrentProcess(),-1);
	}

	int fromlen=sizeof(SOCKADDR);
	*presult=SOCKET_ERROR;
	*presult=recvfrom(m_hSocket,icmpRcvBuf,MAX_PACKET,0,(SOCKADDR*)&m_addrFrom,&fromlen);
		 
	if(*presult==SOCKET_ERROR)
	{
		if(WSAGetLastError()==WSAETIMEDOUT)
		{
			((CTraceRouteDlg*)m_pWnd)->InfoAdd ("接收超时!");
			count++;
			return TRUE;
		}
		AfxMessageBox("接收数据报失败!");
		TerminateProcess(GetCurrentProcess(),-1);
	}
	return FALSE;
}

void CTracer::SetWnd(CDialog *pWnd)
{
	//设置窗口指针。
	m_pWnd=pWnd;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -