socket实现ping命令(控制台)

来源:互联网 发布:双色球彩神通软件 编辑:程序博客网 时间:2024/06/05 19:49
#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 charicmp_type;unsigned charicmp_code;unsigned shorticmp_checksum;unsigned shorticmp_id;unsigned shorticmp_sequence;unsigned longicmp_timestamp;} ICMPHDR, *PICMPHDR;typedef struct tag_iphdr//ip头{UCHARiphVerLen;UCHARipTOS;USHORTipLength;USHORTipID;USHORTipFlags;UCHARipTTL;UCHARipProtacol;USHORTipChecksum;ULONGipSource;ULONGipDestination;} 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;p->icmp_timestamp = 0;}int _tmain(int argc, _TCHAR* argv[]){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 0;}char ip[20];cout << "ping: ";cin >> ip;SOCKADDR_IN addr;//目标主机地址addr.sin_family = AF_INET;addr.sin_addr.S_un.S_addr = inet_addr(ip);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];//接收bufSOCKADDR_IN addrfrom;//接收地址int len = sizeof(SOCKADDR);//地址大小int ipTTL = 0;//TTLwhile (count--){picmp->icmp_checksum = 0;picmp->icmp_timestamp = ::GetTickCount();picmp->icmp_sequence = sequence++;picmp->icmp_checksum = CheckSum((USHORT*)icmp, sizeof(ICMPHDR)+DATA_SIZE);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;}}result = recvfrom(sock, recvbuf, RECV_MAX_SZIE, 0, (SOCKADDR*)&addrfrom, &len);//接收目标主机的icmp应答包if (SOCKET_ERROR == result){if (WSAETIMEDOUT == GetLastError()){cout << "time out" << endl;continue;}else{cout << "recvform error" << endl;closesocket(sock);WSACleanup();return -1;}}int nTick = ::GetTickCount();if (result < sizeof(IPHDR) + sizeof(ICMPHDR) + DATA_SIZE){cout << "too few bytes" << endl;}IPHDR *pIP = (IPHDR*)recvbuf;ipTTL = (int)pIP->ipTTL;//获取目标主机TTLPICMPHDR p = (PICMPHDR)(recvbuf+sizeof(IPHDR));if (p->icmp_type != 0){cout << "error type " << p->icmp_type << " receved" << endl;return -1;}if (p->icmp_id != (USHORT)::GetCurrentProcessId()){cout << "someone else's packet" << endl;return -1;}cout << "reply from: " << inet_ntoa(addrfrom.sin_addr);cout << " data: " << DATA_SIZE << "bytes ";cout << " time: " << nTick-p->icmp_timestamp << "ms";cout << " TTL=" << ipTTL << endl;}return 0;}