基於C語言與原始套接字實現Ping程序

源代碼如下:

ping.h

#pragma pack(1)
//#define u_char unsigned char
//#define u_short unsigned short 
#include<windows.h>
#define ICMP_ECHOREPLY 0
#define ICMP_ECHOREQ 8
//////////////////////////////////
typedef struct tagIPDR
{
	u_char VIHL;//版本和類型
	u_char TOS;//服務質量
	u_char shortTotLen;//長度
    u_char shortID;//編號
	u_char shortFlagOff;//分片,Fragment
	u_char TTL;//生存時間
	u_char Protocol;//協議類型
	u_short Checksum;//校驗和
	struct in_addr iaSrc;//源地址
	struct in_addr isDet;//目的地址
}IPHDR,*PIPHDR;//RFC791 的IP協議頭類型
////////////////////////////////////////
typedef struct tagICMP
{
	u_char Type;//類型
	u_char Code;//代號
	u_short  Checksum;//校驗號
	u_short ID;//標識號
	u_short Seq;//列號
	char Data;//數據信息
}ICMPHDR,*PICMPHDR;//RFC 792 ICMP協議頭
/////////////////////////////////////////
#define REQ_DATASIZE 32
typedef struct tagECHOREQUEST
{
	ICMPHDR icmpHdr;//ICMP協議頭
	DWORD dwTime;//數據傳輸時間
	char cData[REQ_DATASIZE];//傳輸數據
}ECHOREQUEST,*PECHOREQUEST;//請求回傳的數據長度
///////////////////////////////////////////////////
typedef struct tagECHOREPLY
{
	IPHDR ipHdr;
	ECHOREQUEST echoRequest;
	char cFiler[256];
}ECHOREPLY,*PECHOREPLY;//回送請求報文
#pragma pack()


ping.cpp

#include "ping.h"
#include<Winsock.h>
#include<stdlib.h>
#include<stdio.h>
DWORD time;
void Ping(LPCSTR pstrHost);//ping 指令函數;
void ReportError(LPCSTR psrtFrom);
int WaitForEchoReply(SOCKET s);
int SendEchoRequest(SOCKET,LPSOCKADDR_IN);
DWORD RecvEchoReply(SOCKET,LPSOCKADDR_IN,char*);
u_short in_cksum(u_short *addr,int len);
void main()
{
	WSADATA wsaData;
	WORD version=MAKEWORD(1,1);
	char pstrHost[20];
	if(WSAStartup(version,&wsaData))
	{
		printf("初始化協議棧錯誤\n");
		getchar();
		return ;
	}
	if(wsaData.wVersion!=version)
	{
        printf("不支持WIDOWS的套接字\n");
		getchar();
		return ;
	}
	bool flag=true;
	while(flag)
	{
	 printf("Ping>:");
	 scanf("%s",pstrHost);
	 if(strcmp(pstrHost,"exit")==0)
		 break;
	 printf("*****************************\n");
	 Ping(pstrHost);
	}
	WSACleanup();
}
void Ping(LPCSTR pstrHost)
{
	SOCKET rawSocket;
	LPHOSTENT  lpHost;
	struct sockaddr_in saDest;
	struct sockaddr_in saSrc;
	DWORD dwTimeSent;
	DWORD dwElapsed;
	u_char cTTL;
	int nLoop;
	int nRet;
	rawSocket=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
	if(rawSocket==SOCKET_ERROR)
	{
		ReportError("套接字");
		return;
	}
	lpHost=gethostbyname(pstrHost);
   if(lpHost==NULL)
	{
		printf("無法找到這主機[%s]\n",pstrHost);
		getchar();
		return;
	}
	saDest.sin_addr.s_addr=*((u_long FAR*)(lpHost->h_addr));
	saDest.sin_family=AF_INET;
	saDest.sin_port=0;
	printf("\n探測主機%s[%s]:%d字節\n",pstrHost,inet_ntoa(saDest.sin_addr),REQ_DATASIZE);
	for(nLoop=0;nLoop<4;nLoop++)
	{
		SendEchoRequest(rawSocket,&saDest);
		nRet=WaitForEchoReply(rawSocket);
		if(nRet==SOCKET_ERROR)
		{
			ReportError("選擇");
			break;
		}
	   	if(!nRet)
		{
		printf("發送超時\n");	
		break;
		}
		dwTimeSent=RecvEchoReply(rawSocket,&saSrc,(char*)&cTTL);
		dwElapsed=time-dwTimeSent;
	    printf("來自主機[%s]響應,字節:%d 時間:%ld毫秒 最大生存期:%d\n",inet_ntoa(saSrc.sin_addr),REQ_DATASIZE,dwElapsed,cTTL);
	}
       if(closesocket(rawSocket)==SOCKET_ERROR)
		   ReportError("關閉套接字");
}
int SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr)
{
	static ECHOREQUEST echoReq;
	static nId=1;
	static nSeq=1;
	static nRet;
	echoReq.icmpHdr.Type=ICMP_ECHOREQ;
    echoReq.icmpHdr.Code=0;
	echoReq.icmpHdr.Checksum=0;
	echoReq.icmpHdr.ID=nId++;
	echoReq.icmpHdr.Seq=nSeq++;
	for(nRet=0;nRet<REQ_DATASIZE;nRet++)
	  echoReq.cData[nRet]=nRet;
    echoReq.dwTime=GetTickCount();
	time=echoReq.dwTime;//記錄發送時間 
	echoReq.icmpHdr.Checksum=in_cksum((u_short *)&echoReq,sizeof(ECHOREQUEST));
	nRet=sendto(s,(LPCSTR)&echoReq,sizeof(ECHOREQUEST),0,(LPSOCKADDR)lpstToAddr,sizeof(SOCKADDR_IN));
	if(nRet==SOCKET_ERROR)
	 ReportError("發送出錯");
    return nRet;
}
void ReportError(LPCSTR lpStr)
{
	printf("%s發生錯誤,錯誤號:%d\n",lpStr,WSAGetLastError());
	getchar();
}
DWORD RecvEchoReply(SOCKET s,LPSOCKADDR_IN lpsaFrom,char *pTTL)
{
	ECHOREPLY echoReply;
	int nRet;
	int nAddrLen=sizeof(struct sockaddr_in);
    nRet=recvfrom(s,(LPSTR)&echoReply,sizeof(ECHOREPLY),0,(LPSOCKADDR)lpsaFrom,&nAddrLen);
	if(nRet==SOCKET_ERROR)
		ReportError("接收");
	*pTTL=echoReply.ipHdr.TTL;
	return echoReply.echoRequest.dwTime;
}
int WaitForEchoReply(SOCKET s)
{
 struct timeval Timeout;
 fd_set readfds;
 readfds.fd_count=1;
 readfds.fd_array[0]=s;
 Timeout.tv_sec=5;
 Timeout.tv_usec=0;
 return select(1,&readfds,NULL,NULL,&Timeout);
}
u_short in_cksum(u_short *addr,int len)
{
	register int nleft=len;
    register u_short *w=addr;
	register u_short answer;
	register int sum=0;
	while(nleft>1)
	{
		sum+=*w++;
		nleft-=2;
	}
	if(nleft==1)
	{
		u_short u=0;
		*(u_char *)(&u)=*(u_char *)w;
		sum+=u;
	}
	sum=(sum>>16)+(sum&0xffff);
	sum+=(sum>>16);
	answer=~sum;
	return answer;
}

基於VC++6.0直接編譯即可。

發佈了83 篇原創文章 · 獲贊 5 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章