如何测试到网站的连接(ping以及在禁ping的情况下)

 测试到一个网站的连接时间是网络编程中常常要用到的,一般我们可以采用通过发送icmp包ping的方法,但现在有些服务器禁止了ping,
这样用ping的方法就行不通了。但是我们可以换个角度考虑,直接通过HTTP端口(80)来测试,采用mfc中的CInternetSession,以及
CHttpConnection来实现。
本文针对上述两种方法均给出了实现方式,代码如下:

1.ping方式

Ping.h
#pragma pack(4)
#include <winsock2.h>

#define  ICMP_ECHO   8
#define  ICMP_ECHOREPLY  0
#define  ICMP_MIN   8 //icmp包头部的长度

#define  STATUS_FAILED  0xFFFF
#define  DEF_PACKET_SIZE  32
#define  DEF_PACKET_NUMBER 4
#define  MAX_PACKET   1024
#define  NO_RESPONSE   1000

#define  xmalloc(s) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (s))
#define  xfree(p) HeapFree(GetProcessHeap(), 0, (p))

//ip头
typedef struct iphdr
{
 unsigned int version:4; //4位版本
 unsigned int h_len:4; //4位头部长度
 unsigned char tos;  //8位服务类型
 unsigned short total_len; //16位包总长度(字节数)
 unsigned short id;   //16位标识
 unsigned short flag_frag; //3位标志+13位片偏移
 unsigned char ttl;  //8位生存时间
 unsigned char proto;  //8位协议
 unsigned short checksum; //16位首部校验和
 unsigned int srcIP;  //32位源IP地址
 unsigned int dstIP;  //32位目的IP地址
}IpHeader;

//icmp头
typedef struct icmphdr
{
 unsigned char type;  //8位类型
 unsigned char code;  //8位代码
 unsigned short chksum;  //16位校验和
 unsigned short id;   //16位标识
 unsigned short seq;  //16位报文序列号
 unsigned long timesstamp; //32位时间戳
}IcmpHeader;

int ping(const char *szDstIP);
void fill_icmp_data(char *icmp_data, int datasize);
unsigned short checksum(unsigned short *buffer, int size);

Ping.cpp
#include "stdafx.h"
#include "Ping.h"

int ping(const char * szDstIP)
{
 int nRet = NO_RESPONSE;
 SOCKET sockRaw;
 struct sockaddr_in inDest;
 struct sockaddr_in inFrom;
 int nFromLen = sizeof(inFrom);
 unsigned long addr = 0;
 char *icmp_data;
 char *recvbuf;
 unsigned short seq_no = 0;
 int datasize;
 
 sockRaw = socket(AF_INET,SOCK_RAW, IPPROTO_ICMP);
 if (sockRaw == INVALID_SOCKET)
 {
  OutputDebugString("socket error!/n");
  return nRet;
 }
 int bread;
 int timeout = 1000;
 bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout, sizeof(timeout));
 if(bread == SOCKET_ERROR)
 {
  fprintf(stderr,"failed to set recv timeout: %d/n",WSAGetLastError());
  return nRet;
 }
 timeout = 1000;
 bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout, sizeof(timeout));
 if(bread == SOCKET_ERROR)
 {
  fprintf(stderr,"failed to set send timeout: %d/n",WSAGetLastError());
  return nRet;
 }
 memset(&inDest, 0, sizeof(inDest));
 addr = inet_addr(szDstIP);
 inDest.sin_addr.s_addr = addr;
 inDest.sin_family = AF_INET;
 
 datasize = DEF_PACKET_SIZE;
 datasize += sizeof(IcmpHeader);
 icmp_data = (char *)xmalloc(MAX_PACKET);
 if (icmp_data == NULL)
 {
  OutputDebugString("icmp_data is NULL/n");
  return nRet;
 }
 recvbuf = (char *)xmalloc(MAX_PACKET);
 if (recvbuf == NULL)
 {
  OutputDebugString("icmp_data is NULL/n");
  return nRet;
 }
 memset(icmp_data, 0, MAX_PACKET);
 fill_icmp_data(icmp_data, datasize);
 //发送
 int nFirstTime = GetTickCount();
 ((IcmpHeader *)icmp_data)->timesstamp = nFirstTime;
 ((IcmpHeader *)icmp_data)->seq = seq_no++;
 ((IcmpHeader *)icmp_data)->chksum = checksum((unsigned short *)icmp_data, datasize);
 int nSend;
 nSend = sendto(sockRaw, icmp_data, datasize, 0, (const SOCKADDR *)&inDest, sizeof(inDest));
 if (nSend == SOCKET_ERROR)
 {
  return nRet;
 }
 
 int nRecv;
 nRecv = recvfrom(sockRaw, recvbuf, MAX_PACKET, 0, (SOCKADDR *)&inFrom, &nFromLen);
 if (nRecv == SOCKET_ERROR)
 {
  return nRet;
 }
 nRet = GetTickCount() - nFirstTime;
 return nRet;
}

//填充icmp数据(头+主体)
void fill_icmp_data(char *icmp_data, int datasize)
{
 IcmpHeader *icmp_hdr;
 char *datapart;
 icmp_hdr = (IcmpHeader *)icmp_data;
 icmp_hdr->type = ICMP_ECHO;
 icmp_hdr->code = 0;
 icmp_hdr->id = (unsigned short)GetCurrentProcessId();
 icmp_hdr->chksum = 0;
 icmp_hdr->seq = 0;
 datapart = icmp_data + sizeof(IcmpHeader);

 //填充数据全部为A
 memset(datapart, 'A', datasize - sizeof(IcmpHeader));
}

unsigned short checksum(unsigned short *buffer, int size)
{
 unsigned long chksum = 0;
 while (size > 1)
 {
  chksum += *buffer++;
  size -= sizeof(unsigned short);
 }
 if (size)
 {
  chksum += *(unsigned char *)buffer;
 }
 chksum = (chksum >> 16) + (chksum & 0xffff);
 chksum += (chksum >> 16);
 return (unsigned short)(~chksum);
}

2. HTTP方式

MyPing.h

#include <afxinet.h>

class CMySession : public CInternetSession
{
public:
 CMySession(LPCTSTR pszAppName, int nMethod);
 virtual void OnStatusCallback(DWORD dwContext, DWORD dwInternetStatus,
  LPVOID lpvStatusInfomration, DWORD dwStatusInformationLen);
};


class CMyException : public CException
{
 DECLARE_DYNCREATE(CMyException)

public:
 CMyException(int nCode = 0);
 ~CMyException() { }

 int m_nErrorCode;
};

int geturl(CString szServerName);

MyPing.cpp
#include "stdafx.h"
#include "MyPing.h"

#pragma warning(push)
#pragma warning(disable: 4100 4667)
#include <iostream>
#pragma warning(pop)
using namespace std;
#include <stdlib.h>

/
// Globals

LPCTSTR pszURL = NULL;
BOOL    bStripMode = FALSE;
BOOL    bProgressMode = FALSE;
DWORD   dwAccessType = PRE_CONFIG_INTERNET_ACCESS;

DWORD dwHttpRequestFlags =
INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_AUTO_REDIRECT;

const TCHAR szHeaders[] =
_T("Accept: text/*/r/nUser-Agent: MFC_Tear_Sample/r/n");

/
// CMySession object

CMySession::CMySession(LPCTSTR pszAppName, int nMethod)
: CInternetSession(pszAppName, 1, nMethod)
{
}

void CMySession::OnStatusCallback(DWORD /* dwContext */, DWORD dwInternetStatus,
         LPVOID /* lpvStatusInfomration */, DWORD /* dwStatusInformationLen */)
{
 if (!bProgressMode)
  return;

 if (dwInternetStatus == INTERNET_STATUS_CONNECTED_TO_SERVER)
  cerr << _T("Connection made!") << endl;
}

IMPLEMENT_DYNCREATE(CMyException, CException)

CMyException::CMyException(int nCode)
: m_nErrorCode(nCode)
{
}

void ThrowMyException(int nCode)
{
 CMyException* pEx = new CMyException(nCode);
 throw pEx;
}

/
// Routines

int geturl(CString szServerName)

 int nFirstTime = GetTickCount();
 int nRetCode = 0;

 CMySession session(_T("geturl"), dwAccessType);
 CHttpConnection* pServer = NULL;
 CHttpFile* pFile = NULL;
 try
 {
  // check to see if this is a reasonable URL

  CString strServerName(szServerName);
  if (strServerName.Find("http://") == -1)
  {
   strServerName = "http://" + strServerName;
  }
  CString strObject;
  INTERNET_PORT nPort = INTERNET_DEFAULT_HTTP_PORT;
  DWORD dwServiceType;

  pServer = session.GetHttpConnection(strServerName, nPort);

  pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET,
   strObject, NULL, 1, NULL, NULL, dwHttpRequestFlags);
  pFile->AddRequestHeaders(szHeaders);
  pFile->SendRequest();

  DWORD dwRet;
  pFile->QueryInfoStatusCode(dwRet);

  // if access was denied, prompt the user for the password

  if (dwRet == HTTP_STATUS_DENIED)
  {
   DWORD dwPrompt;
   dwPrompt = pFile->ErrorDlg(NULL, ERROR_INTERNET_INCORRECT_PASSWORD,
    FLAGS_ERROR_UI_FLAGS_GENERATE_DATA | FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, NULL);

   // if the user cancelled the dialog, bail out

   if (dwPrompt != ERROR_INTERNET_FORCE_RETRY)
   {
    cerr << _T("Access denied: Invalid password/n");
    ThrowMyException(1);
   }

   pFile->SendRequest();
   pFile->QueryInfoStatusCode(dwRet);
  }

  CString strNewLocation;
  pFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, strNewLocation);

  // were we redirected?
  // these response status codes come from WININET.H

  if (dwRet == HTTP_STATUS_MOVED ||
   dwRet == HTTP_STATUS_REDIRECT ||
   dwRet == HTTP_STATUS_REDIRECT_METHOD)
  {
   CString strNewLocation;
   pFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, strNewLocation);

   int nPlace = strNewLocation.Find(_T("Location: "));
   if (nPlace == -1)
   {
    cerr << _T("Error: Site redirects with no new location") << endl;
    ThrowMyException(2);
   }

   strNewLocation = strNewLocation.Mid(nPlace + 10);
   nPlace = strNewLocation.Find('/n');
   if (nPlace > 0)
    strNewLocation = strNewLocation.Left(nPlace);

   // close up the redirected site

   pFile->Close();
   delete pFile;
   pServer->Close();
   delete pServer;

   if (bProgressMode)
   {
    cerr << _T("Caution: redirected to ");
    cerr << (LPCTSTR) strNewLocation << endl;
   }

   // figure out what the old place was
   if (!AfxParseURL(strNewLocation, dwServiceType, strServerName, strObject, nPort))
   {
    cerr << _T("Error: the redirected URL could not be parsed.") << endl;
    ThrowMyException(2);
   }

   if (dwServiceType != INTERNET_SERVICE_HTTP)
   {
    cerr << _T("Error: the redirected URL does not reference a HTTP resource.") << endl;
    ThrowMyException(2);
   }

   // try again at the new location
   pServer = session.GetHttpConnection(strServerName, nPort);
   pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET,
    strObject, NULL, 1, NULL, NULL, dwHttpRequestFlags);
   pFile->AddRequestHeaders(szHeaders);
   pFile->SendRequest();

   pFile->QueryInfoStatusCode(dwRet);
   if (dwRet != HTTP_STATUS_OK)
   {
    cerr << _T("Error: Got status code ") << dwRet << endl;
    ThrowMyException(2);
   }
  }

  cerr << _T("Status Code is ") << dwRet << endl;

  pFile->Close();
  pServer->Close();
 }
 catch (CInternetException* pEx)
 {
  // catch errors from WinINet

  TCHAR szErr[1024];
  pEx->GetErrorMessage(szErr, 1024);

  cerr << _T("Error: (") << pEx->m_dwError << _T(") ");
  cerr << szErr << endl;

  nRetCode = 2;
  pEx->Delete();
 }
 catch (CMyException* pEx)
 {
  // catch things wrong with parameters, etc

  nRetCode = pEx->m_nErrorCode;
  TRACE1("Error: Exiting with CTearException(%d)/n", nRetCode);
  pEx->Delete();
 }

 if (pFile != NULL)
  delete pFile;
 if (pServer != NULL)
  delete pServer;
 session.Close();
 nRetCode = GetTickCount() - nFirstTime;
 return nRetCode;
}

使用方法如下:
void CPageWebSet::OnBnClickedButtonTest()
{
 // TODO: 在此添加控件通知处理程序代码
 CWaitCursor cursor;
 UpdateData(TRUE);
 int nIndex = m_strUrl.MakeLower().Find("http://");
 if (nIndex != -1)
 {
  m_strUrl = m_strUrl.Mid(7, m_strUrl.GetLength() - 7);
 }
 struct hostent *pHost;
 pHost = gethostbyname((LPCTSTR)m_strUrl);
 char szIP[20];
 struct sockaddr_in inIP;
 memcpy(&inIP.sin_addr.s_addr, pHost->h_addr_list[0], pHost->h_length);
 strcpy(szIP, inet_ntoa(inIP.sin_addr));
 int nPintTime = ping(szIP);
 if (nPintTime == NO_RESPONSE)
 {
  m_strUrlInfo.Format("Ping " + m_strUrl + " Time Out/r/n");
  nPintTime = geturl(m_strUrl);
  CString strTmp;
  strTmp.Format("try another way to connect " + m_strUrl + " Time:%d" , nPintTime);
  m_strUrlInfo += strTmp;
 }
 else
 {
  m_strUrlInfo.Format("Ping " + m_strUrl + " Time:%d" , nPintTime);
 }
 UpdateData(FALSE);
 cursor.Restore();
}

当然,上面的方法肯定存在不足之处,本文也是旨在给出一个初步的方案,希望大家能更好的完善。
有新的想法记得告诉我一声~~,我的qq:27548274,msn:zqsxmu@hotmail.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值