开发学院软件开发VC 使用ICMP实现路由跟踪 阅读

使用ICMP实现路由跟踪

 2010-06-27 20:40:36 来源:WEB开发网   
核心提示:五、添加代码在完成了对各控件的设置和类的添加以后就是对代码的编写了,这里给出了新建类CICMP和RouteTraceDlg.cpp的代码,使用ICMP实现路由跟踪(3),详细代码请参看源程序,ICMP.cpp文件代码:// ICMP.cpp: implementation of the CICMP class.#inc

五、添加代码

在完成了对各控件的设置和类的添加以后就是对代码的编写了,这里给出了新建类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 清华大学出版社

本文配套源码

上一页  1 2 3 

Tags:使用 ICMP 实现

编辑录入:爽爽 [复制链接] [打 印]
[]
  • 好
  • 好的评价 如果觉得好,就请您
      0%(0)
  • 差
  • 差的评价 如果觉得差,就请您
      0%(0)
赞助商链接