自己写的一个ping程序

 以前学习ICMP协议时候写的一个模仿windows自带的ping程序。程序没有经过仔细的测试,估计还有点问题,如果你发现程序中的BUG,请发一封email到 yzljlss#126.com (为防止垃圾邮件,@用#替换)告诉我。3Q。

 

/******************************************************************
    
        程序:  myping
        功能:  模拟ping命令
        O/S :   WINDOWS 98或更高版本
        作者:  严政
        时间:  2007.8.14
        版本变更:
                V1.0.0   2007.8.14  初始版本,实现了基本的ping功能 
        说明:  
                这是开源代码,你可以随意拷贝使用。如果你有好的建议或
                意见,发E-mail至: [ yzljlss@126.com ]讨论。
******************************************************************
*/

#include 
< stdio.h >
#include 
< WINSOCK2.H >

#pragma  comment(lib,"wsock32.lib")
#pragma  comment(lib,"Ws2_32.lib")

#define  SIO_RECALL _WSAIOW(IOC_VENDOR,1)
#define  MAX_HOSTNAME_LEN 256

sockaddr_in LocalAddr,SendAddr,destAddr;
SOCKET sock;

struct  hostent FAR  * pHostent,  * pTmp;

int  total  =   4 ; // 发送ping报文次数,默认为4次
int  seconds  =   0 ; // 发送时间间隔
bool  hostToIp  =   false ; // -a 将目标的机器标识转换为ip地址 
bool  pingforever  =   false ; // -t 若使用者不人为中断会不断的ping下去
bool  isCount  =   false ; // -c count 要求ping命令连续发送count个数据包
bool  isSimple  =   false ; // -q ping只在开始和结束时打印一些概要信息

char  FAR name[MAX_HOSTNAME_LEN];
char  destIP[ 16 ]; // 目标IP

typedef 
struct  _ping
{
    UCHAR i_type;
//8位类型
    UCHAR i_code;//8位代码
    USHORT i_chksum;//16位ICMP校验和
    USHORT i_identify;//16位标志位
    USHORT i_seqnum;//16位序号
    ULONG    i_timestamp;//32位时间戳
    UCHAR i_data[32];//32BYTE选项数据
}
PingHeader, * pPingHeader;

typedef 
struct      _ipHeader // IP头部,总长度20字节
{
#if LITTLEENDIAN
    UCHAR IpHlen:
4,        //4位首部长度
          IpVer :4;        //4位IP版本号
#else
    UCHAR   IpVer :
4,        //4位IP版本号
            IpHlen:4;        //4位首部长度
#endif
    UCHAR  IpTos;
//8服务类型
    USHORT IpTlen;//总长度
    USHORT IpId;//标志    
    USHORT FlagsOff;//分片偏移
    UCHAR  IpTtl;//生存时间
    UCHAR  IpProto;//协议    
    USHORT ChkSum;//检验和
    struct in_addr   SourIp;//源IP地址    
    struct in_addr   DestIp; //目的IP地址
}
 IpHeader, * pIpHeader;

// 求校验和
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  help()
{
    printf(
"==========================[ myping V1.0.0 ]============================ ");
    printf(
" 用法: myping [-a] [-t] [-c count] [-i seconds] [-q] [-h] target_IP ");
    printf(
"参数: ");
    printf(
" -a     将目标的机器标识转换为ip地址 ");
    printf(
"     建议: ping远程主机时不要添加此参数,否则速度较慢 ");
    printf(
" -t     若使用者不人为中断会不断的ping下去 ");
    printf(
" -c count    要求ping命令连续发送count个数据包 ");
    printf(
" -i seconds  在两次数据包发送之间间隔一定的秒数 ");
    printf(
" -q     myping只在开始和结束时打印一些概要信息 ");
    printf(
" -h     帮助信息 ");
    printf(
"例如: myping -a -i 1 -c 10 192.168.0.100 ");
    printf(
"=========================[ By 严政 07.8.14 ]=========================== ");
}


// 发送,解析PING报文
int  funPing()
{
    unsigned 
long i,
        totalrecv
=0;//收到包的数目
    unsigned long addr, timestamp,
        maxtime 
= 0,//最大延迟
        mintime = 0;//最小延迟
    PingHeader ping,*ping_hdr;
    
char recv_buff[65535];
    
char szDestIP[16];
    
int recvLen;

    pIpHeader ip_hdr;

    SendAddr.sin_family 
= AF_INET;
    SendAddr.sin_addr.s_addr 
= inet_addr(destIP);
    
    
if(hostToIp)
    
{
        memset(name, 
0, MAX_HOSTNAME_LEN);
        
//获取ping对象主机名
        addr = inet_addr(destIP);
        pHostent 
= gethostbyaddr((char *)&addr, sizeof(destIP) , AF_INET);
        
if(pHostent == NULL)
        
{
            
//printf("fail to get host name: %d ",WSAGetLastError());
            fprintf(stdout, "Ping %s with 32 bytes of datas: ",destIP);
        }

        
else
            fprintf(stdout, 
"Ping %s[ %s ] with 32 bytes of datas: ", pHostent->h_name, destIP);
    }
            
    
else
        fprintf(stdout, 
"Ping %s with 32 bytes of datas: ",destIP);
    
    
for(i=0;;i++)
    
{
        
if(!pingforever)
        
{
            
if(i >= (unsigned long)total)//达到发送次数
                break;
        }

        
        
//填充PING报文
        ping.i_type = 8;
        ping.i_code 
= 0;
        ping.i_seqnum 
= (USHORT)i;
        ping.i_identify 
= (unsigned short)GetCurrentProcessId(); 
        ping.i_timestamp 
= (unsigned long)::GetTickCount();
        
for(int j=0;j < 32; j++)
            ping.i_data[i] 
= (UCHAR)('a'+j);
        ping.i_chksum 
= 0;
        
//计算校验和
        ping.i_chksum = checksum((unsigned short*)&ping,sizeof(ping));
        
//printf("checksum=%d ",ping.i_chksum);
        
        
if(sendto(sock, (char*)&ping, sizeof(ping),0, (struct sockaddr*)&SendAddr, sizeof(SendAddr)) == SOCKET_ERROR)
        
{
            printf(
"Send ping packet error: %d ",WSAGetLastError());
            
return -1;
        }

        
        memset(recv_buff, 
01024);
        
int len = sizeof(destAddr);
        
if((recvLen = recvfrom(sock, recv_buff, sizeof(recv_buff), 0, (struct sockaddr*)&destAddr, &len)) == SOCKET_ERROR)
        
{
            
int err = WSAGetLastError();
            
if(err != 10060)//超时错误不返回
            {
                printf(
"recv data error: %d ",err);
                
return -1;
            }

            
else if(!isSimple)
                fprintf(stdout, 
"请求超时. ");
        }

        
if(recvLen > 0)
        
{
            
            
//处理接收的IP报文,解析PING应答报文
            ip_hdr = (pIpHeader)recv_buff;

            memcpy(szDestIP, inet_ntoa(ip_hdr
->SourIp), 16);
            
if(ip_hdr->IpProto == IPPROTO_ICMP && !strcmp(szDestIP, destIP))//处理来自PING对象且是ICMP的报文
            {
                ping_hdr 
= (pPingHeader)(recv_buff + sizeof(unsigned long)*ip_hdr->IpHlen);
                
            
//    fprintf(stdout,"ping_hdr.i_type=%02X ",ping_hdr->i_type);
            
//    fprintf(stdout,"ping_hdr.i_code=%02X ",ping_hdr->i_code);
            
//    fprintf(stdout,"ping_hdr.i_seqnum=%04X ",ping_hdr->i_seqnum);
            
//    fprintf(stdout,"ping_hdr.i_identify=%04X ",ping_hdr->i_identify);
            
//    fprintf(stdout,"ping_hdr.timestamp=%08X ",ping_hdr->i_timestamp);
                
//应答报文
                if(ping_hdr->i_type == 0)
                
{
                    
//计算延迟时间
                    timestamp = (unsigned long)::GetTickCount();
                    timestamp 
-= ping_hdr->i_timestamp;
                    
if(i == 0)
                        mintime 
= timestamp;
                    maxtime 
= (timestamp > maxtime) ? timestamp : maxtime;//最大延迟时间
                    mintime = (timestamp < mintime) ? timestamp : mintime;//最小延迟时间

                    
if(timestamp == 0)
                        timestamp 
= 1;
                    
if(!isSimple)
                        fprintf(stdout, 
"Reply from %s: bytes=%d time<%dms TTL=%d ", destIP, 
                            
sizeof(ping_hdr->i_data), timestamp, ip_hdr->IpTtl );
                    
//收到包的数目
                    totalrecv++;
                }

                
if(ping_hdr->i_type == 3)
                
{
                    fprintf(stdout, 
"目的不可达");
                    
switch(ping_hdr->i_code)
                    
{
                    
case 0:
                        fprintf(stdout, 
"(网络不可达) ");
                        
break;
                    
case 1:
                        fprintf(stdout, 
"(主机不可达) ");
                        
break;
                    
case 2:
                        fprintf(stdout, 
"(协议不可达) ");
                        
break;
                    
case 3:
                        fprintf(stdout, 
"(端口不可达) ");
                        
break;
                    
default:
                        
break;
                    }

                }

                
if(ping_hdr->i_type == 5)
                
{
                    
if(ping_hdr->i_code == 0)
                        fprintf(stdout, 
"对网络重定向. ");
                    
if(ping_hdr->i_code == 1)
                        fprintf(stdout, 
"对主机重定向. ");
                }

                
            }

        }

        Sleep(seconds);
    }
//end for
    
    
//计算ping统计信息
    fprintf(stdout, " Ping %s 的统计信息: ",destIP);
    fprintf(stdout, 
" 包: 发送 = %d, 收到 = %d, 丢失 = %d (丢失率: %.0f%%) ",
        i, totalrecv, (i
-totalrecv), ((float)(i-totalrecv))/i*100 );
    
if(totalrecv != 0)//没收到包打印路由信息无意义
    {
        fprintf(stdout, 
"近似路由时间(毫秒): ");
        fprintf(stdout, 
" 最大 = %dms, 最小 = %dms, 平均 = %dms ", maxtime, mintime, (maxtime+mintime)/2);
    }

    
return 0;
}


int  main( int  argc,  char *  argv[])
{
    DWORD lpvBuffer 
= 1;
    DWORD lpcbBytesReturned 
= 0;
    
    
int nNetTimeout=3000;//超时3秒
    
    
//初始化套结字
    WSADATA WSAData;
    
if(WSAStartup(MAKEWORD(2,2), &WSAData) != 0)
    
{
        printf(
"fail to init socket: %d",WSAGetLastError());
        
return -1;
    }

    
//创建套结字
    sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (
char *)&nNetTimeout,sizeof(int));

    
if(sock == SOCKET_ERROR)
    
{
        printf(
"fail to create socket: %d",WSAGetLastError());
        
return -1;
    }

    
//获取本机IP
    if(gethostname(name, MAX_HOSTNAME_LEN))
    
{
        printf(
"get host name error: %d",WSAGetLastError());
        
return -1;
    }

    pHostent 
= (struct hostent *)malloc(sizeof(struct hostent));
    pTmp 
= pHostent;
    pHostent 
= gethostbyname(name);
 
    LocalAddr.sin_family 
= AF_INET;
    LocalAddr.sin_port 
= htons(0);
    memcpy(
&LocalAddr.sin_addr.S_un.S_addr, pHostent->h_addr_list[0], pHostent->h_length);
    
    
//bind socket
    if(bind(sock, (struct sockaddr *)&LocalAddr, sizeof(LocalAddr)) == SOCKET_ERROR)
    
{
        printf(
"bind error: %d",WSAGetLastError());
        
return -1;
    }

/*     
    //置网卡为混杂模式
    //在这个ping程序中,不能将网卡置于混杂模式,否则接收的报文包括自己发送的报文 (^_^)
    if(WSAIoctl(sock, SIO_RECALL, &lpvBuffer ,sizeof(lpvBuffer), NULL, 0,
        &lpcbBytesReturned, NULL, NULL) == SOCKET_ERROR)
    {
        printf("WSAIoctl(...) error: %d",WSAGetLastError());
        return -1;
    }
*/
    
    
//命令行解析
    if(argc < 2)
    
{
        printf(
"必须输入ping参数! ");
        help();
        
return -1;
    }

    
else
    
{
        
for(int i=1; i < argc; i++)
        
{
            
if(argv[i][0== '-')
            
{
                
switch( (tolower(argv[i][1])) )
                
{
                
case 'a':
                    hostToIp 
= true;
                    
break;
                
case 't':
                    pingforever 
= true;
                    
break;
                
case 'h':
                    help();
                    
return -1;
                    
break;
                
case 'q'://ping只在开始和结束时打印一些概要信息
                    isSimple = true;
                    
break;
                
case 'c':
                    
{
                        
if*(argv[i]+3> '9' || *(argv[i]+3< '0' )
                        
{
                            printf(
"ping次数错误参数! ");
                            help();
                            
return -1;
                        }

                        
//发送报文次数
                        total = atoi(argv[++i]);
                        
break;
                    }

                
case 'i'://设置发送报文时间差
                    {
                        
if*(argv[i]+3> '9' || *(argv[i]+3< '0' )
                        
{
                            printf(
"时间错误参数! ");
                            help();
                            
return -1;
                        }

                        
//发送报文次数
                        seconds = atoi(argv[++i]) * 1000;
                        
break;
                    }

                
default:
                    
break;
                }
//end switch
            }
//end if
        }
//end for
        
        
if( (argv[argc-1][0]) > '9' || (argv[argc-1][0]) < '0' )
        
{
            printf(
"目的IP错误!请确认最后一个参数是目的IP. ");
            help();
            
return -1;
        }

        
        memcpy(destIP, argv[argc
-1], strlen(argv[argc-1]));
    }

    
//发送ping报文
    funPing();

    free(pTmp);
    closesocket(sock);
    WSACleanup();

    
return 0;
}
### 回答1: 好的,我可以帮你一个基本的 ping 测试程序。在这里我们假设你已经知道了 ping 命令的基本用法。 首先,你需要使用 Python 的 `subprocess` 模块来调用系统的 ping 命令。你可以使用 `subprocess.run` 方法来执行命令,然后捕获它的输出。 ```python import subprocess def ping(host): result = subprocess.run(['ping', '-c', '3', host], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) return result.stdout ``` 这样你就可以使用 `ping` 函数来测试一个主机的连通性了,例如: ```python print(ping("www.example.com")) ``` 这样你就可以看到 ping 命令的输出了。 如果你想要更复杂的功能,例如解析 ping 的输出以获取更多信息,或者根据测试的结果执行不同的操作,你可以对代码进行进一步的完善。 希望这对你有帮助! ### 回答2: 当然可以帮你一个ping测试程序Ping是一种网络工具,用于测试网络连接的延迟和可用性。以下是一个简单的示例程序: ```python import os def ping(host): response = os.system("ping -c 1 " + host) if response == 0: return "主机 " + host + " 可以正常访问。" else: return "主机 " + host + " 无法访问。" host = input("请输入要测试的主机IP地址或域名:") result = ping(host) print(result) ``` 这个程序使用了Python的`os`模块,调用系统命令执行ping操作。它接收一个参数`host`,即要测试的主机IP地址或域名。程序会执行一次ping操作,然后根据返回的结果判断主机是否可以正常访问。 你可以运行这个程序,并输入你想要测试的主机IP地址或域名。程序会输出测试结果,告诉你主机是否可以正常访问。 请注意,这只是一个基本的示例程序,可能无法处理复杂的网络环境或特殊情况。在实际使用中,你可能需要根据具体需求对程序进行修改和扩展。 ### 回答3: ping测试程序是一种用于测试网络连接的工具。它通过向目标主机发送一个ICMP回显请求(ping请求),然后等待主机的回应(ping响应)来判断网络连接的质量和延迟情况。 在编这个程序之前,我们需要安装Python的第三方库`ping3`,它可以用于执行ping测试。你可以使用以下命令在终端安装该库: ``` pip install ping3 ``` 接下来,我们可以编一个简单的ping测试程序,如下所示: ```python from ping3 import ping, verbose_ping def ping_test(hostname): # 执行ping测试 delay = ping(hostname) # 输出结果 if delay is not None: print(f'成功连接到主机 {hostname},延迟为 {delay:.2f} 毫秒。') else: print(f'无法连接到主机 {hostname}。') def verbose_ping_test(hostname): # 执行详细ping测试 delay, _, _, _, _ = verbose_ping(hostname) # 输出结果 if delay is not None: print(f'成功连接到主机 {hostname},延迟为 {delay:.2f} 毫秒。') else: print(f'无法连接到主机 {hostname}。') # 示例用法1:执行简单ping测试 ping_test('www.example.com') # 示例用法2:执行详细ping测试 verbose_ping_test('www.example.com') ``` 上述程序中,我们使用了`ping3`库的`ping`和`verbose_ping`函数执行ping测试,并根据返回的结果输出连接状态和延迟信息。 你可以将`www.example.com`替换为你想要测试的主机名或IP地址,然后运行程序进行测试。程序将输出成功连接或无法连接的结果,并显示延迟时间。 希望以上内容能够帮助你编一个简单的ping测试程序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值