socket实现tracert命令(控制台)

来源:互联网 发布:网络优化电子书 编辑:程序博客网 时间:2024/05/21 18:44
#include <winsock2.h>#include <iostream>#include <windows.h>using namespace std;#define DATA_SIZE 32//icmp包数据大小#define RECV_MAX_SZIE 1024//接收的数据最大长度#define IP_TTL 4//optname#define MAX_HOP 30//最大跃点数#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{unsigned charip_verlen; unsigned charip_tos; unsigned shortip_totallength; unsigned shortip_id; unsigned shortip_offset; unsigned charip_ttl; unsigned charip_protocol; unsigned shortip_checksum; unsigned intip_srcaddr; unsigned intip_destaddr; } IPHDR, *PIPHDR;void FillIcmp(char *icmp){PICMPHDR p = (PICMPHDR)icmp;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;}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);}int g_size = sizeof(ICMPHDR)+DATA_SIZE;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 << "tracert:";cin >> ip;cout << endl << "Tracing route to" << ip << "[" << ip << "]" << "with a maximum of 30 hops." << endl << endl;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 bOpt = 1;int outTime = 2000;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(g_size);//为icmp包申请内存memset(icmp, 0, g_size);//内存空间置零FillIcmp(icmp);//填充icmp包unsigned short sequence = 0;//序列号int count = 4;//发送请求次数char recvbuf[RECV_MAX_SZIE];//接收bufSOCKADDR_IN addrfrom;//接收地址int len = sizeof(SOCKADDR);//地址大小int ttl = 1;//TTLint result;while (1){result = setsockopt(sock, IPPROTO_IP, IP_TTL, (char*)&ttl, sizeof(int));if (SOCKET_ERROR == result){cout << "setsockopt IP_TTL error" << endl;closesocket(sock);WSACleanup();return -1;}((PICMPHDR)icmp)->icmp_checksum = 0;((PICMPHDR)icmp)->icmp_checksum = CheckSum((USHORT*)icmp, g_size);int nTickPre = ::GetTickCount();result = sendto(sock, icmp, g_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超时”报文(ttl等于0)if (SOCKET_ERROR == result){if (WSAETIMEDOUT == GetLastError()){cout << ttl << ":"  << "*"<< "time out" << endl;++ttl;continue;}else{cout << "recvform error" << endl;closesocket(sock);WSACleanup();return -1;}}int nTickNow = ::GetTickCount();int time = nTickNow - nTickPre;PIPHDR pip = (PIPHDR)recvbuf;char sip[20];in_addr srcaddr;srcaddr.S_un.S_addr = pip->ip_srcaddr;strcpy(sip, inet_ntoa(srcaddr));if (time == 0)cout << ttl << ":"  <<  "<1ms"<< sip << endl;elsecout << ttl << ":"  << time << "ms"<< sip << endl;if (strcmp(ip, sip) == 0){cout << "tracert complete" << endl;break;}++ttl;if (ttl > 30){break;}}return 0;}

原创粉丝点击