- 论坛徽章:
- 0
|
主代码如下:
#include "winsock2.h"
#include "stdio.h"
#pragma comment(lib,"WS2_32")
#pragma comment(lib,"winmm.lib")
#include "comm.h"
#include "initsock.h"
#include "Ws2tcpip.h"
#include "protoinfo.h"
typedef struct icmp_hdr
{
unsigned char icmp_type;
unsigned char icmp_code;
unsigned short icmp_checksum;
unsigned short icmp_id;
unsigned short icmp_sequence;
unsigned long icmp_timestamp;
}ICMP_HDR,*PICMP_HDR;
USHORT checksum(USHORT* buff, int size)
{
unsigned long cksum = 0;
while(size>1)
{
cksum += *buff++;
size -= sizeof(USHORT);
}
// 是奇数
if(size)
{
cksum += *(UCHAR*)buff;
}
// 将32位的chsum高16位和低16位相加,然后取反
cksum = (cksum >> 16) + (cksum & 0xffff);
//cksum += (cksum >> 16);
return (USHORT)(~cksum);
}
BOOL SetTTL(SOCKET s, int nValue)
{
int ret = ::setsockopt(s, IPPROTO_IP, IP_TTL, (char*)&nValue, sizeof(nValue));
return ret != SOCKET_ERROR;
}
BOOL SetTimeout(SOCKET s, int nTime, BOOL bRecv)
{
int ret = ::setsockopt(s, SOL_SOCKET,
bRecv ? SO_RCVTIMEO : SO_SNDTIMEO, (char*)&nTime, sizeof(nTime));
return ret != SOCKET_ERROR;
}
int main(int argc, char* argv[])
{
WSADATA wsaData;
int wsaret = WSAStartup(0x101,&wsaData);
SOCKET sRaw = ::socket(AF_INET , SOCK_RAW , IPPROTO_ICMP );
SetTimeout(sRaw , 5000 , true);
sockaddr_in dest;
dest.sin_family = AF_INET;
dest.sin_port = htons(0);
dest.sin_addr.S_un.S_addr = inet_addr(argv[1]);
// dest.sin_addr.S_un.S_addr = inet_addr(ip);
char buff[sizeof(ICMP_HDR)+32];
ICMP_HDR* pIcmp = (ICMP_HDR*)buff;
pIcmp->icmp_type = 8;
pIcmp->icmp_code = 0;
pIcmp->icmp_id = (USHORT)::GetCurrentProcessId();
pIcmp->icmp_checksum = 0;
pIcmp->icmp_sequence= 0;
memset(&buff[sizeof(ICMP_HDR)], 'a' ,32);
USHORT nSeq = 0;
char recvBuf[1024];
sockaddr_in from;
int nLen = sizeof(from);
while(true)
{
static int nCount = 0;
int nRet;
if (nCount++ ==4) break;
pIcmp->icmp_checksum = 0;
// pIcmp->icmp_timestamp = ::GetTickCount();
pIcmp->icmp_timestamp = ::timeGetTime();
pIcmp->icmp_sequence = nSeq++;
pIcmp->icmp_checksum = checksum((USHORT*)buff,sizeof(ICMP_HDR)+32);
nRet = ::sendto(sRaw , buff , sizeof(ICMP_HDR)+32 , 0,(sockaddr*)&dest,sizeof(dest));
if(nRet == SOCKET_ERROR)
{
printf("sendto() failed:%d\n",::WSAGetLastError());
return -1;
}
memset(recvBuf,'\0',1024);
nRet = ::recvfrom(sRaw,recvBuf,1024,0,(sockaddr*)&from,&nLen);
if(nRet == SOCKET_ERROR)
{
if(::WSAGetLastError() == WSAETIMEDOUT)
{
printf("time out\n");
continue;
}
printf("recvfrom() failed\n");
return -1;
}
int nTick = ::timeGetTime();
if(nRet < sizeof(IPHeader)+sizeof(ICMP_HDR))
{
printf("Too few bytes from %s \n",::inet_ntoa(from.sin_addr));
}
ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf +sizeof(IPHeader));
if (pRecvIcmp->icmp_type !=0)
{
printf("nonecho type %d recvd \n",pRecvIcmp->icmp_type);
return -1;
}
if(pRecvIcmp->icmp_id != ::GetCurrentProcessId())
{
printf("someone else's packet!\n");
return -1;
}
printf("%s\n",recvBuf+sizeof(IPHeader)+sizeof(ICMP_HDR));
printf("%d bytes from %s:",nRet,inet_ntoa(from.sin_addr));
printf("icmp_seq = %d:",pRecvIcmp->icmp_sequence);
printf("time:%d ms", nTick - pRecvIcmp->icmp_timestamp);
printf("\n");
::Sleep(1000);
}
return 0;
}
在其中有::sendto()以及recvfrom()函数。
这两个函数究竟是什么关系?
可不可以不使用sendto 直接使用recvfrom()? |
|