该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
我在用socket 的API写一个traceroute的程序,发送的是ICMP数据包,完成后发现程序跑两三遍没问题,但是之后的话,程序便不能运行了,我查看了一下,ICMP的type类型返回了9,应该返回0的,求教为什么?总是成功两三遍后就没法运行,重开也没有用,只能重启电脑才行。小弟多谢各位了,顺便吐槽下头衔的名字。程序如下
#include "TraceRoute1.h"
void ConnectToHost(char* strHost)
{
m_nTTL = 1;
m_nMaxhops = MAX_HOPS;
m_sockRaw = INVALID_SOCKET;
m_RcvBuffer = NULL;
m_IcmpData = NULL;
m_nTimeout = 1000;
m_bDone = FALSE;
WSADATA wsaData; //存储被WSAStartup函数调用后返回的Windows Sockets数据
if (WSAStartup(MAKEWORD(2,2),&wsaData) != 0)
{
printf("初始化出错\n"); //如果结果不为0,初始化WinSock出错
}
m_sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, //返回新套接口的描述字,失败就返回INVALID_SOCKET
NULL, 0,WSA_FLAG_OVERLAPPED);
//m_sockRaw = 4294967291;
if (m_sockRaw == INVALID_SOCKET)
{
printf("创建套接口出错\n");
ExitProcess(-1);
}
int ret = setsockopt(m_sockRaw, SOL_SOCKET, SO_RCVTIMEO, //设置套接口的属性
(char *)&m_nTimeout, sizeof(m_nTimeout));
if (ret == SOCKET_ERROR) //若无错误发生,setsockopt()返回0。否则的话,返回SOCKET_ERROR错误
{
printf("设置套接口属性出错(接收)\n"); //获得上次失败操作的错误状态.
return ;
}
ret = setsockopt(m_sockRaw, SOL_SOCKET, SO_SNDTIMEO,
(char *)&m_nTimeout, sizeof(m_nTimeout));
if (ret == SOCKET_ERROR)
{
printf("设置套接口属性出错(发送)\n");
return ;
}
//解析地址
m_addrDest.sin_family = AF_INET; //给变量赋值
if ((m_addrDest.sin_addr.s_addr = inet_addr(strHost)) == INADDR_NONE) // 将函数inet_addr(strHost)取得的结果付给变量
//将一个点分十进制的IP转换成一个长整数型数(
// 然后判断两个变量是否相等
{
HOSTENT* hp;
hp = gethostbyname(strHost); //返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针
if (hp)
memcpy(&(m_addrDest.sin_addr), hp->h_addr, hp->h_length); //取指针地址所指的变量,放入函数 memcpy中计算得到结果
else
{
printf("地址解析错误\n");
return ;
}
}
//设置路由选项
int bOpt = TRUE;
if (setsockopt(m_sockRaw, SOL_SOCKET, SO_DONTROUTE, (char *)&bOpt,
sizeof(BOOL)) == SOCKET_ERROR)
{
printf("设置套接口选项失败\n");
return ;
}
m_nDatasize = DEF_PACKET_SIZE;
m_nDatasize += sizeof(IcmpHeader);
//
//为icmp 数据包分配发送和接收缓冲区
m_IcmpData = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PACKET);
m_RcvBuffer = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PACKET);
//为icmp 数据包分配发送和接收缓冲区
if ((!m_IcmpData) || (!m_RcvBuffer))
{
printf("icmp缓冲区分配失败\n");
return ;
}
//创建icmp数据包
memset(m_IcmpData, 0, MAX_PACKET);
printf("\n追踪目的主机 %s: \n\n", strHost);
fill_icmp_data(m_IcmpData, m_nDatasize);
for(m_nTTL = 1; ((m_nTTL < m_nMaxhops) && (!m_bDone)); m_nTTL++)
{
int bwrote;
set_ttl(m_sockRaw, m_nTTL);
((IcmpHeader*)m_IcmpData)->i_cksum = 0;
((IcmpHeader*)m_IcmpData)->timestamp = GetTickCount(); //返回时间
((IcmpHeader*)m_IcmpData)->i_seq = m_nSeqno++;
((IcmpHeader*)m_IcmpData)->i_cksum = checksum((USHORT*)m_IcmpData,
m_nDatasize);
//发送icmp包到目的端
bwrote = sendto(m_sockRaw, m_IcmpData, m_nDatasize, 0,
(SOCKADDR *)&m_addrDest, sizeof(m_addrDest));
if (bwrote == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAETIMEDOUT)
{
printf("%2d 发送超时.\n", m_nTTL);
continue;
}
printf("发送数据出错\n");
return ;
}
//从目的端读取数据报
int fromlen;
fromlen = sizeof(SOCKADDR);
ret = recvfrom(m_sockRaw, m_RcvBuffer, MAX_PACKET, 0,
(struct sockaddr*)&m_addrFrom, &fromlen);
if (ret == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAETIMEDOUT)
{
printf("接受超时\n");
continue;
}
printf("接受数据出错\n");
return ;
}
m_bDone = decode_resp(m_RcvBuffer, ret, &m_addrFrom, m_nTTL);
Sleep(1000);
}
}
void fill_icmp_data(char * icmp_data, int datasize)
{
IcmpHeader *icmp_hdr;
char *datapart;
icmp_hdr = (IcmpHeader*)icmp_data;
icmp_hdr->i_type = ICMP_ECHO;
icmp_hdr->i_code = 0;
icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
icmp_hdr->i_cksum = 0;
icmp_hdr->i_seq = 0;
datapart = icmp_data + sizeof(IcmpHeader);
memset(datapart,'0', datasize - sizeof(IcmpHeader));
}
int set_ttl(SOCKET s, int nTimeToLive)
{
int nRet;
nRet = setsockopt(s, IPPROTO_IP, IP_TTL, (LPSTR)&nTimeToLive,
sizeof(int));
if (nRet == SOCKET_ERROR)
{
printf("设置套接字选项出错\n");
return 0;
}
return 1;
}
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while(size > 1)
{
cksum += *buffer++;
size -= sizeof(USHORT);
}
if(size )
cksum += *(UCHAR*)buffer;
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (USHORT)(~cksum);
}
//释放
void Cleanup()
{
HeapFree(GetProcessHeap(), 0, m_RcvBuffer);
HeapFree(GetProcessHeap(), 0, m_IcmpData);
if (m_sockRaw != NULL)
closesocket(m_sockRaw);
WSACleanup();
}
int decode_resp(char *buf, int bytes, SOCKADDR_IN *from, int ttl)
{
IpHeader *iphdr = NULL;
IcmpHeader *icmphdr = NULL;
unsigned short iphdrlen;
struct hostent *lpHostent = NULL;
struct in_addr inaddr = from->sin_addr;
iphdr = (IpHeader *)buf;
// 32位word转化成byte要*4
iphdrlen = iphdr->h_len * 4;
icmphdr = (IcmpHeader*)(buf + iphdrlen);
//ICMP首部的地址等于IP首部长度+buf
switch (icmphdr->i_type)
{
case ICMP_ECHOREPLY: // 目的地址返回的icmp
lpHostent = gethostbyaddr((const char *)&from->sin_addr,
AF_INET, sizeof(struct in_addr));
if (lpHostent != NULL)
printf("%2d %s (%s)\n", ttl, lpHostent->h_name,
inet_ntoa(inaddr)); //将一个IP转换成一个互联网标准点分格式的字符串。
return 1;
break;
case ICMP_TIMEOUT: // 沿着这条链路返回的路由
printf("%2d %s\n", ttl, inet_ntoa(inaddr));
return 0;
break;
default:
printf("错误!\n");
return 1;
break;
}
return 0;
}