1. 程式人生 > >socket實現ping功能

socket實現ping功能

#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; }