這幾天在學socket網路編程。拿socket寫個ping操練一下。
自己寫的運行后recv一直會出現10060(接收超時)的錯誤。但用cmd下的ping和網上別人的碼都可以的。(測得127.0.0.1)
以下是代碼。該得都跟網上copy下來成功的代碼差不多了,真是沒招了。求指正!
#include "iostream"
#include <string>
#include <winsock2.h>
using namespace std;
#pragma comment(lib, "Ws2_32.lib") // 加載Ws2_32.lib
typedef struct icmp_header
{
unsigned char icmp_type;//訊息型別
unsigned char icmp_code;//代碼
unsigned short icmp_checksum;//校驗和
unsigned short icmp_id;//用來標示此請求的ID號,通常設定為行程ID
unsigned short icmp_sequence;//序列號
unsigned long icmp_timestamp;//時間戳
} icmp_header, *PICMPHDR;
#define ICMP_HEADER_SIZE sizeof(icmp_header)
#define ICMP_ECHO_REQUEST 0x08
#define ICMP_ECHO_REPLY 0x00
//計算校驗和
unsigned short chsum(struct icmp_header *picmp, int len)
{
long sum = 0;
unsigned short *pusicmp = (unsigned short *)picmp;
while (len < 1)
{
sum += *(pusicmp++);
if (sum & 0x80000000)
{
sum = (sum & 0xffff) + (sum >> 16);
}
len -= 2;
}
if (len)
{
sum += (unsigned short)*(unsigned char *)pusicmp;
}
while (sum >> 16)
{
sum = (sum & 0xffff) + (sum >> 16);
}
return (unsigned short)~sum;
}
//SOCK錯誤處理程式
void CheckSockError(int nErrorCode, char *pErrorMsg)
{
// printf("I am here\n");
printf("nErrorCode%d\n", nErrorCode);
if (nErrorCode == SOCKET_ERROR) {
printf("s Error:d\n", pErrorMsg, GetLastError());
// closesocket(nSockRaw);
// ExitProcess(-1);
}
}
bool MyPing(char *szDestIp)
{
bool bRet = TRUE;
char icmp_data[32] = { 0 };
WSADATA wsadata;
WSAStartup(MAKEWORD(2, 2), &wsadata);
//設定目的地址
sockaddr_in dest_addr;
ZeroMemory(&dest_addr, sizeof(sockaddr_in));
dest_addr.sin_family = AF_INET;
dest_addr.sin_addr.S_un.S_addr = inet_addr(szDestIp);
dest_addr.sin_port = htons(0);
// dest_addr.sin_addr.s_addr = szDestIp;
//創建原始套接字
// SOCKET s = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, WSA_FLAG_OVERLAPPED);
SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
CheckSockError(s, "setsockopt()");
DWORD dwError1 = WSAGetLastError();
printf("ErrorCode%d\n", dwError1);
int nErrorCode;
int nTimeOut = 1000;
nErrorCode = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char const*)&nTimeOut, sizeof(int)); //設定發送超時
if (SOCKET_ERROR == nErrorCode)
{
cout << "setsockopt erro" << endl;
closesocket(s);
WSACleanup();
return -1;
}
//設定接收超時
nErrorCode = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char const*)&nTimeOut, sizeof(int));
CheckSockError(nErrorCode, "setsockopt()");
DWORD dwError2 = WSAGetLastError();
printf("ErrorCode%d\n", dwError2);
char szBuff[ICMP_HEADER_SIZE + 32] = { 0 };
memset(szBuff, 0, sizeof(szBuff));
icmp_header *pIcmp = (icmp_header *)szBuff;
//構造ICMP封包
pIcmp->icmp_type = ICMP_ECHO_REQUEST;
pIcmp->icmp_code = 0;
pIcmp->icmp_checksum = 0;
pIcmp->icmp_id = (USHORT)::GetCurrentProcessId();
pIcmp->icmp_sequence = 0;
pIcmp->icmp_timestamp = 0;
unsigned short sequence = 0; //序列號
int count = 4;
char szRecvBuff[1024];
sockaddr_in from_addr;
int nLen = sizeof(SOCKADDR);
//拷貝資料
memcpy((szBuff + ICMP_HEADER_SIZE), "abcdefghijklmnopqrstuvwabcdefghi", 32);
// memset(szRecvBuff, 0, sizeof(szRecvBuff));
while (count--){
pIcmp->icmp_checksum = 0;
pIcmp->icmp_timestamp = ::GetTickCount();
pIcmp->icmp_sequence = sequence++;
//計算校驗和
pIcmp->icmp_checksum = chsum((struct icmp_header *) szBuff, sizeof(szBuff));
int result;
result = sendto(s, szBuff, sizeof(szBuff), 0, (SOCKADDR *)&dest_addr, sizeof(dest_addr));
CheckSockError(result, "sendto()");
DWORD dwError3 = WSAGetLastError();
printf("ErrorCode%d\n", dwError3);
result = recvfrom(s, szRecvBuff, MAXBYTE, 0, (SOCKADDR *)&from_addr, &nLen);
CheckSockError(result, "recv()");
DWORD dwError4 = WSAGetLastError();
printf("ErrorCode%d\n", dwError4);
printf("recv = %s", szBuff);
int length = strlen(szBuff);
if (length > 0)
{
cout << szBuff
<< "This IP is online"
<< "收到位元組數"<<length
<< endl;
}
else
{
cout << "This IP is not online" << endl;
}
cout << inet_ntoa(from_addr.sin_addr) << endl;
cout << szDestIp << endl;
//判斷接收到的是否是自己請求的地址
if (lstrcmp(inet_ntoa(from_addr.sin_addr), szDestIp))
{
bRet = FALSE;
}
else
{
struct icmp_header *pIcmp1 = (icmp_header *)(szRecvBuff + 20);
printf("%s\r\n", inet_ntoa(from_addr.sin_addr));
}
}
closesocket(s);
WSACleanup();
return bRet;
}
void main()
{
cout<<"Which do you want to ping?"<<endl;
char Destip[20];
cin >> Destip;
// char *Destip;
// Destip = &ip[0];
if (MyPing(Destip))
{
cout << "This is right"<<endl;
}
else
{
cout << "This seems not right" << endl;
}
system("pause");
}
uj5u.com熱心網友回復:
拿別人的代碼和自己的對比, 或者慢慢看 RFC792 標準uj5u.com熱心網友回復:
你想用捉包工具看看你的包發送出來沒,格式對不對。uj5u.com熱心網友回復:
你對比一下代碼不就清楚了~uj5u.com熱心網友回復:
ping需要管理員權限uj5u.com熱心網友回復:
127.0.0.1還能超時?本地的地址都不走路由。。超時應該是代碼的問題了吧,用BCompare工具比較下代碼uj5u.com熱心網友回復:
僅供參考:#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#include <mmsystem.h>
#pragma comment(lib, "ws2_32")
#pragma comment(lib, "winmm")
#define ICMP_ECHOREPLY 0 //ICMP回應答復
#define ICMP_ECHOREQ 8 //ICMP回應請求
#define REQ_DATASIZE 32 //請求資料報大小
#include <iostream>
using namespace std;
//定義IP首部格式
typedef struct _IPHeader {
u_char VIHL; //版本和首部長度
u_char ToS; //服務型別
u_short TotalLen; //總長度
u_short ID; //標識號
u_short Frag_Flags; //片偏移量
u_char TTL; //生存時間
u_char Protocol; //協議
u_short Checksum; //首部校驗和
struct in_addr SrcIP; //源IP地址
struct in_addr DestIP; //目的地址
}
IPHDR, *PIPHDR;
//定義ICMP首部格式
typedef struct _ICMPHeader {
u_char Type; //型別
u_char Code; //代碼
u_short Checksum; //首部校驗和
u_short ID; //標識
u_short Seq; //序列號
char Data; //資料
}
ICMPHDR, *PICMPHDR;
//定義ICMP回應請求
typedef struct _ECHOREQUEST {
ICMPHDR icmpHdr;
DWORD dwTime;
char cData[REQ_DATASIZE];
}
ECHOREQUEST, *PECHOREQUEST;
//定義ICMP回應答復
typedef struct _ECHOREPLY {
IPHDR ipHdr;
ECHOREQUEST echoRequest;
char cFiller[256];
}
ECHOREPLY, *PECHOREPLY;
//計算校驗和
u_short checksum(u_short *buffer, int len) {
register int nleft = len;
register u_short *w = buffer;
register u_short answer;
register int sum = 0;
//使用32位累加器,進行16位的反饋計算
while ( nleft > 1 ) {
sum += *w++;
nleft -= 2;
}
//補全奇數位
if ( nleft == 1 ) {
u_short u = 0;
*(u_char *)(&u) = *(u_char*)w;
sum += u;
}
//將反饋的16位從高位移到低位
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
//發送回應請求函式
int SendEchoRequest(SOCKET s, struct sockaddr_in *lpstToAddr) {
static ECHOREQUEST echoReq;
static int nId = 1;
static int nSeq = 1;
int nRet;
//填充回應請求訊息
echoReq.icmpHdr.Type = ICMP_ECHOREQ;
echoReq.icmpHdr.Code = 0;
echoReq.icmpHdr.Checksum = 0;
echoReq.icmpHdr.ID = nId++;
echoReq.icmpHdr.Seq = nSeq++;
//填充要發送的資料
for (nRet = 0; nRet < REQ_DATASIZE; nRet++) {
echoReq.cData[nRet] = '1' + nRet;
}
//存盤發送的時間
echoReq.dwTime = timeGetTime();
//計算回應請求的校驗和
echoReq.icmpHdr.Checksum = checksum((u_short*)&echoReq, sizeof(ECHOREQUEST));
//發送回應請求
nRet = sendto(s,(LPSTR)&echoReq,sizeof(ECHOREQUEST),
0,(struct sockaddr*)lpstToAddr,sizeof(SOCKADDR_IN));
if (nRet == SOCKET_ERROR) {
printf("send to() error:%d\n", WSAGetLastError());
}
return (nRet);
}
//接收應答回復并進行決議
DWORD RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL) {
ECHOREPLY echoReply;
int nRet;
int nAddrLen = sizeof(struct sockaddr_in);
//接收應答回復
nRet = recvfrom(s,(LPSTR)&echoReply,sizeof(ECHOREPLY),
0,(LPSOCKADDR)lpsaFrom,&nAddrLen);
//檢驗接收結果
if (nRet == SOCKET_ERROR) {
printf("recvfrom() error:%d\n",WSAGetLastError());
}
//記錄回傳的TTL
*pTTL = echoReply.ipHdr.TTL;
//回傳應答時間
return(echoReply.echoRequest.dwTime);
}
//等待回應答復,使用select模型
int WaitForEchoReply(SOCKET s) {
struct timeval timeout;
fd_set readfds;
readfds.fd_count = 1;
readfds.fd_array[0] = s;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
return(select(1, &readfds, NULL, NULL, &timeout));
}
//PING功能實作
void Ping(char *pstrHost,bool logic) {
SOCKET rawSocket;
LPHOSTENT lpHost;
struct sockaddr_in destIP;
struct sockaddr_in srcIP;
DWORD dwTimeSent;
DWORD dwElapsed;
u_char cTTL;
int nLoop,k=4;
int nRet,minimum=100000,maximum=0,average=0;
int sent=4,reveived=0,lost=0;
//創建原始套接字,ICMP型別
rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (rawSocket == SOCKET_ERROR) {
printf("socket() error:%d\n", WSAGetLastError());
return;
}
//檢測目標主機
lpHost = gethostbyname(pstrHost);
if (lpHost==NULL) {
printf("Host not found:%s\n", pstrHost);
return;
}
//設定目標機地址
destIP.sin_addr.s_addr = *((u_long FAR*)(lpHost->h_addr)); //設定目標IP
destIP.sin_family = AF_INET; //地址規格
destIP.sin_port = 0;
//提示開始進行PING
printf("\nPinging %s [%s] with %d bytes of data:\n",pstrHost,inet_ntoa(destIP.sin_addr),REQ_DATASIZE);
//發起多次PING測驗
for (nLoop=0; nLoop<k; nLoop++) {
if (logic)k=k+1;
//發送ICMP回應請求
SendEchoRequest(rawSocket, &destIP);
//等待回復的資料
nRet = WaitForEchoReply(rawSocket);
if (nRet == SOCKET_ERROR) {
printf("select() error:%d\n", WSAGetLastError());
break;
}
if (!nRet) {
lost++;
printf("\nRequest time out.");
continue;
}
//接識訓復
dwTimeSent = RecvEchoReply(rawSocket, &srcIP, &cTTL);
reveived++;
//計算花費的時間
dwElapsed = timeGetTime() - dwTimeSent;
if(dwElapsed>maximum)maximum=dwElapsed;
if(dwElapsed<minimum)minimum=dwElapsed;
average+=dwElapsed;
printf("\nReply from %s: bytes = %d time = %ldms TTL = %d",
inet_ntoa(srcIP.sin_addr),REQ_DATASIZE,dwElapsed,cTTL);
}
printf("\n\n");
printf("Ping statistics for %s:\n",inet_ntoa(srcIP.sin_addr));
printf(" Packets: Sent = %d, Received = %d, Lost = %d (%.f%% loss),\n",
sent,reveived,lost,(float)(lost*1.0/sent)*100);
if(lost==0) {
printf("Approximate round trip times in milli-seconds:\n");
printf(" Minimum = %dms, Maximum = %dms, Average = %dms\n",minimum,maximum,average/sent);
}
printf("\n\n");
nRet = closesocket(rawSocket);
if (nRet == SOCKET_ERROR) {
printf("closesocket() error:%d\n", WSAGetLastError());
}
}
void main() {
printf("Welcome to the Ping Test\n");
while(1) {
WSADATA wsd;//檢測輸入的引數
//初始化Winsock
if (WSAStartup(MAKEWORD(1, 1), &wsd) != 0) {
printf("加載 Winsock 失敗!\n");
}
char opt1[100];
char *ptr=opt1;
bool log=false;
printf("Ping ");
cin.getline(opt1,100,'\n');
if ((opt1[0]=='-')&&(opt1[1]=='t')&&(opt1[2]==' ')) {
log=true;
ptr=opt1+3;
}
//開始PING
Ping(ptr,log);
//程式釋放 Winsock 資源
WSACleanup();
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/129743.html
標籤:網絡編程
