socket實現ping功能
阿新 • • 發佈:2019-02-05
#include <winsock2.h>
#include <iostream>
#include <windows.h>
using namespace std;
#define DATA_SIZE 32
#define RECV_MAX_SZIE 1024
#pragma comment(lib, "ws2_32.lib")
typedef struct tag_icmphdr //icmp頭
{
unsigned char icmp_type;
unsigned char icmp_code;
unsigned short icmp_checksum;
unsigned short icmp_id;
unsigned short icmp_sequence;
} ICMPHDR, *PICMPHDR;
typedef struct tag_iphdr //ip頭
{
UCHAR iphVerLen;
UCHAR ipTOS;
USHORT ipLength;
USHORT ipID;
USHORT ipFlags;
UCHAR ipTTL;
UCHAR ipProtacol;
USHORT ipChecksum;
ULONG ipSource;
ULONG ipDestination;
} IPHDR;
USHORT CheckSum(USHORT *buf,int size)
{
USHORT cksum=0;
while(size>1)
{
cksum+=*buf++;
size-=sizeof(USHORT);
}
if(size)
cksum+=*buf++;
cksum=(cksum>>16)+(cksum&0xffff);
cksum+=(cksum>>16);
return (USHORT)(~cksum);
}
void FillIcmp(PICMPHDR p)
{
p->icmp_type = 8 ;
p->icmp_code = 0;
p->icmp_checksum = 0;
p->icmp_id = (unsigned short)::GetCurrentProcessId();
p->icmp_sequence = 0;
}
int main()
{
WORD version = MAKEWORD(2,2);
WSADATA data;
WSAStartup(version, &data);
if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2)
{
cout << "WSAStartup failed" << endl;
WSACleanup();
return -1;
}
char host[] = "www.baidu.com";
struct hostent *he = gethostbyname(host);
if (!he)
{
return -1;
}
struct in_addr **addr_list = (struct in_addr **) he->h_addr_list;
SOCKADDR_IN addr; //目標主機地址
addr.sin_family = AF_INET;
addr.sin_addr = *addr_list[0];
addr.sin_port = htons(0);
SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); //建立原始套接字
int outTime = 1000;
int rst;
rst = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&outTime, sizeof(int)); //設定傳送超時
if (SOCKET_ERROR == rst)
{
cout << "setsockopt erro" << endl;
closesocket(sock);
WSACleanup();
return -1;
}
rst = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&outTime, sizeof(int)); //設定接收超時
if (SOCKET_ERROR == rst)
{
cout << "setsockopt erro" << endl;
closesocket(sock);
WSACleanup();
return -1;
}
char *icmp = (char*)malloc(sizeof(ICMPHDR)+DATA_SIZE); //為icmp包申請記憶體
memset(icmp, 0, sizeof(ICMPHDR)+DATA_SIZE); //記憶體空間置零
PICMPHDR picmp = (PICMPHDR)icmp;
FillIcmp(picmp); //填充icmp包
unsigned short sequence = 0; //序列號
int count = 4; //傳送請求次數
char recvbuf[RECV_MAX_SZIE]; //接收buf
SOCKADDR_IN addrfrom; //接收地址
int len = sizeof(SOCKADDR); //地址大小
int ipTTL = 0; //TTL
while (count--)
{
picmp->icmp_checksum = 0;
picmp->icmp_sequence = sequence++;
picmp->icmp_checksum = CheckSum((USHORT*)icmp, sizeof(ICMPHDR)+DATA_SIZE);
DWORD send_ts = ::GetTickCount();
int result;
result = sendto(sock, icmp, sizeof(ICMPHDR)+DATA_SIZE, 0, (SOCKADDR*)&addr, sizeof(SOCKADDR)); //向目標主機發送icmp請求包
if (SOCKET_ERROR == result)
{
if (WSAETIMEDOUT == WSAGetLastError())
{
cout << "time out" << endl;
continue;
}
else
{
cout << "sendto error" << endl;
closesocket(sock);
WSACleanup();
return -1;
}
}
while ((result = recvfrom(sock, recvbuf, RECV_MAX_SZIE, 0, (SOCKADDR*)&addrfrom, &len)) > 0)
{
if (addr.sin_addr.s_addr == addrfrom.sin_addr.s_addr)
{
break;
}
}
if (SOCKET_ERROR == result)
{
if (WSAETIMEDOUT == GetLastError())
{
cout << "time out" << endl;
continue;
}
else
{
cout << "recvform error" << endl;
closesocket(sock);
WSACleanup();
return -1;
}
}
DWORD recv_ts = ::GetTickCount();
if (result < sizeof(IPHDR) + sizeof(ICMPHDR) + DATA_SIZE)
{
cout << "too few bytes" << endl;
}
IPHDR *pIP = (IPHDR*)recvbuf;
ipTTL = (int)pIP->ipTTL; //獲取目標主機TTL
PICMPHDR p = (PICMPHDR)(recvbuf+sizeof(IPHDR));
if (p->icmp_type != 0)
{
cout << "error type " << p->icmp_type << " receved" << endl;
return -1;
}
cout << "reply from: " << inet_ntoa(addrfrom.sin_addr) << " time: " << recv_ts - send_ts << "ms" << " TTL=" << ipTTL << endl;
}
getchar();
return 0;
}