科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件VC下使用ICMP实现路由跟踪

VC下使用ICMP实现路由跟踪

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文简单介绍了ICMP协议和在VC 下实现网络路由跟踪的方法,并给出详细的例子 。

作者:UNNY 来源:论坛 2007年10月21日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
五、添加代码

  在完成了对各控件的设置和类的添加以后就是对代码的编写了,这里给出了新建类CICMP和RouteTraceDlg.cpp的代码,详细代码请参看源程序。

  ICMP.cpp文件代码:

// ICMP.cpp: implementation of the CICMP class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "RouteTrace.h"
#include "ICMP.h"
#include "ws2tcpip.h" //实现 IP_TTL 设置的关键

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

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

CICMP::CICMP()
{
winsock = 0;
m_pIp = NULL;
m_pIcmp = NULL;

m_pIp = (IP_HEAD *)new BYTE[MAX_PACKET];
m_pIcmp = (ICMP_HEAD *)new BYTE[MAX_PACKET];

}

CICMP::~CICMP()
{
delete [] m_pIp;
delete [] m_pIcmp;
}

BOOL CICMP::Initialize()
{
WSADATA wsadata;
if( WSAStartup(MAKEWORD(2, 1),&wsadata) )
{
AfxMessageBox("WSAStartup初始化失败!");
return FALSE;
}

winsock= WSASocket (AF_INET, //建立socket
SOCK_RAW,
IPPROTO_ICMP,
NULL, 0,0);
if(!winsock) {
AfxMessageBox( "Socket创建失败!");
return FALSE;
}

int timeout =5000;
setsockopt(winsock,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout, // 设置接收超时
sizeof(timeout));
timeout = 5000;
setsockopt(winsock,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout, //设置发送超时
sizeof(timeout));

return TRUE;
}

void CICMP::Uninitialize() //释放Socket
{
if(winsock)
closesocket(winsock);
WSACleanup();
}

USHORT CICMP::CheckSum(USHORT *buffer, int size) //计算校验和
{
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);
}
//--------------------发送ICMP回应请求报文-------------------

BOOL CICMP::SendICMPPack(char *pAddr)
{
sockaddr_in sockAddr;
memset((void *)&sockAddr,0,sizeof(sockAddr));
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = 0;
sockAddr.sin_addr.S_un.S_addr=inet_addr(pAddr);

return SendICMPPack(&sockAddr);
}
BOOL CICMP::SendICMPPack(sockaddr_in *pAddr)
{
//填充ICMP数据各项
int state;
char *p_data;
m_pIcmp->type = ICMP_ECHO;
m_pIcmp->code = 0;
m_pIcmp->ID = (USHORT)GetCurrentProcessId();
m_pIcmp->number = 0;
m_pIcmp->time = GetTickCount();
m_pIcmp->cksum = 0;

//填充数据
p_data = ((char *)m_pIcmp + sizeof(ICMP_HEAD));
memset((char *)p_data,''0'',DEF_PACKET);

//校验和
m_pIcmp->cksum = CheckSum((USHORT *)m_pIcmp,
DEF_PACKET+sizeof(ICMP_HEAD));

//发送数据
state = sendto(winsock,(char *)m_pIcmp,
DEF_PACKET+sizeof(ICMP_HEAD),
NULL,(struct sockaddr *)pAddr,sizeof(sockaddr));

if(state == SOCKET_ERROR) {
if(GetLastError()==WSAETIMEDOUT)
m_strInfo = "连接超时!(发送)";
else
m_strInfo.Format("出现未知发送错误!");
return FALSE;
}

if(state <DEF_PACKET) {
m_strInfo = "发送数据错误!";
return FALSE;
}

memcpy((void *)&m_sockAddr,(void *)pAddr,
sizeof(sockaddr_in));

return TRUE;
}

//----------------------接收数据----------------------------
BOOL CICMP::RecvICMPPack()
{
int state;
int len = sizeof(sockaddr_in);
char * addr;
struct hostent *lpHostent = NULL;

addr = inet_ntoa(m_sockAddr.sin_addr);
state = recvfrom(winsock,(char *)m_pIp,MAX_PACKET,0,
(struct sockaddr*)&m_sockAddr,&len);

if (state == SOCKET_ERROR) {
if (WSAGetLastError() == WSAETIMEDOUT)
{ m_strInfo="接收超时,路由跟踪失败!";
routestate=0;
RouteState="路由跟踪失败!";
}
else
m_strInfo = "未知接收错误!";
return FALSE;
}

//分析数据
int ipheadlen;
ipheadlen = m_pIp->HeadLen * 4 ;

if (state < (ipheadlen+MIN_PACKET)) {
m_strInfo = "目的地址的响应数据不正确";
return FALSE;
}

ICMP_HEAD * p_icmprev;
p_icmprev = (ICMP_HEAD*)((char *)m_pIp + ipheadlen);

switch (p_icmprev->type)
{
case ICMP_ECHOREPLY: //收到正常回显
{
m_strInfo.Format("接收到%s %d字节响应数据,响应时间:%dms.",
inet_ntoa(m_sockAddr.sin_addr),len,GetTickCount()-p_icmprev->time);
routeaddr=addr;
routestate=0;
RouteState="到达目的主机!";
return TRUE;
break;
}
case ICMP_TTLOUT: // TTL超时
{ routeaddr=inet_ntoa(m_sockAddr.sin_addr);
routestate=1;
RouteState="测试到路由器!";
return TRUE;
break;
}

case ICMP_DESUNREACH: //目的不可达
{ m_strInfo = "目的不可达!";
routestate=0;
RouteState="目的不可达!";
return TRUE;
break;
}

default :{ routestate=0;
m_strInfo="未知错误!";
RouteState="不明状态!";
}
}
return TRUE;

}
//----------------设置TTL--------------------
int CICMP::SetTTL(int TTL)
{
int nRet=setsockopt(winsock, IPPROTO_IP, IP_TTL,(LPSTR)&TTL,sizeof(int));

if(nRet==SOCKET_ERROR)
{ CString ttlerr;
ttlerr.Format("设置 TTL 错误!");
AfxMessageBox(ttlerr);
return 0;
}
return 1;
}

RouteTraceDlg.cpp文件代码:// RouteTraceDlg.cpp : implementation file
//
#include "stdafx.h"
#include "RouteTrace.h"
#include "RouteTraceDlg.h"
#include "afxmt.h"


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

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
struct SubThreadInfo
{
CDialog* pDialog;
CListCtrl* list;
CStatic* state;
CString IPStr;
int Maxhot;

} Info;

CEvent eventStopRoute;
//-----------------路由跟踪线程---------------
UINT ThreadRoute(LPVOID pParam)
{
SubThreadInfo* pInfo = (SubThreadInfo*)pParam;
CRouteTraceDlg* pThreadDlg = (CRouteTraceDlg*)pInfo->pDialog;

CICMP m_icmp;
CString IPStr=pInfo->IPStr;
CString sTTL;
int nTtl;
m_icmp.Initialize();
for(nTtl=1;nTtl<=pInfo->Maxhot;nTtl++)
{
if(m_icmp.SetTTL(nTtl)==0)
return 0;
sTTL.Format("%d",nTtl);
if(m_icmp.SendICMPPack((char *)(LPCSTR)IPStr))
m_icmp.RecvICMPPack();


{
int i=pInfo->list->InsertItem(0,sTTL);
pInfo->list->SetItemText(i,1,m_icmp.routeaddr);
pInfo->list->SetItemText(i,2,m_icmp.RouteState);
pInfo->state->SetWindowText(m_icmp.m_strInfo);
Sleep(100);
}
if(m_icmp.routestate==0) //收到非TTL超时报文则跳出循环
break;
if(WaitForSingleObject(eventStopRoute.m_hObject, 0) == WAIT_OBJECT_0)
break; //收到停止信号则跳出循环
}
pThreadDlg->Routeflag=TRUE;

return 0;
}

…… //系统代码

BOOL CRouteTraceDlg::OnInitDialog()
{
CDialog::OnInitDialog();

…… //系统代码

// TODO: Add extra initialization here
m_list.InsertColumn(0,"标号",LVCFMT_CENTER,60,0);
m_list.InsertColumn(1,"路由器地址",HDF_CENTER,200,0);
m_list.InsertColumn(2,"状态",HDF_CENTER,100,0);

ListView_SetExtendedListViewStyleEx(m_list.m_hWnd, LVS_EX_FULLROWSELECT, 0xFFFFFFFF);

return TRUE; // return TRUE unless you set the focus to a control
}

…… //系统代码

void CRouteTraceDlg::OnTrace()
{
CString str;
UpdateData(TRUE);
CWnd * pWnd;
pWnd = GetDlgItem(IDC_COMBO);
pWnd->GetWindowText(str);

if(str.IsEmpty()) {
MessageBox("请输入地址!");
pWnd->SetFocus();
return;
}
if (m_comb.FindStringExact(-1, str) == CB_ERR)
m_comb.AddString(str);

m_list.DeleteAllItems();
if(Routeflag)
{
Routeflag=FALSE;
Info.IPStr=str;
Info.pDialog=this;
Info.Maxhot=m_maxhot;
Info.list=(&m_list);
Info.state=(&m_statectl);
AfxBeginThread(ThreadRoute, &Info); //在线程中实现路由跟踪
}
}

void CRouteTraceDlg::OnStop()
{
if(!Routeflag)
{
eventStopRoute.SetEvent(); // 发出停止信号
}
}

void CRouteTraceDlg::OnDestroy()
{
CDialog::OnDestroy();

// TODO: Add your message handler code here
m_icmp.Uninitialize();
}

  代码运行效果图如下:



  源代码下载

  六、结束语

  本文所述程序在 Windows 98 下 Visual C++6.0 中调试通过,并在宽带网中测试成功。读者可根据实际需要修改程序中的参数,以实现更强大的功能,比如可以把超时值设置成更合适的值,或设置成可动态输入的形式,示例程序请看本文所附源码。

  七、参考文献

  1. 胡晓军、邓波、高宏伟 编著 Visual C++高级开发范例解析 2002.1 电子工业出版社

  2. 周明天、汪文勇 编著 TCP/IP网络原理与技术  1993.12 清华大学出版社

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章