Ping命令的设计与实现

ping命令的设计与实现

发表于 C++ Socket TCP/IP 2016-05-15 19:07 字数: 10796 阅读量: 528

ping 命令使用的相关 TCP/IP 协议

ping 命令是用来查看网络上另一个主机系统的网络连接是否正常的一个工具。

ping 命令执行后显示出被测试系统主机名和相应 IP 地址、返回给当前主机的 ICMP 报文顺序号、ttl 生存时间和往返时间 rtt(单位是毫秒,即千分之一秒)。

ping 命令所使用到的 TCP/IP 协议:ICMP 协议:

ICMP 是(Internet Control Message Protocol)Internet 控制报文协议。它是 TCP/IP 协议族的一个子协议,用于在 IP 主机、路由器之间传递控制消息。

控制消息有:目的不可达消息,超时信息,重定向消息,时间戳请求和时间戳响应消息,回显请求和回显应答消息。

ping 命令使用回显请求和回显应答消息。具体表现是向网络上的另一个主机系统发送 ICMP 报文,如果指定系统得到了报文,它将把报文一模一样地传回给发送者。


回显请求报文其中类型为 0,代码为 0。

回显应答报文其中类型为 8,代码为 0。

校验和字段:包括数据在内的整个 ICMP 协议数据包的校验和

标识符字段:用于唯一标识 ICMP 报文,本项目使用程序的进程 id。因为如果同时在两个命令行终端执行 ping 命令的话,每个 ping 命令都会接收到所有的回显应答,所以需要根据标识符来判断回显应答是否应该接收。

序号字段:ICMP 报文的序号。

数据字段:也就是报文,本项目中我们将发送报文的时间戳放入数据字段,这样当接收到该报文应答的时候可以取出发送时间戳,将接收应答的时间戳减去发送时间戳就是报文往返时间(rtt)。

ICMP 报文实现可以用下面的数据结构表示:


1

2

3

4

5

6

7

8

struct icmp{

    unsigned char   type;         // 类型

    unsigned char   code;         // 代码

    unsigned short  checksum;     // 校验和

    unsigned short  id;            // 标识符

    unsigned short  sequence;     // 序号

    struct timeval  timestamp;    // 时间戳

};

unsigned char 正好一字节,也就是 8bit,unsigned short 二字节,也就是 16bit,unsigned int4 字节(32bit).

系统发送ICMP报文时会将ICMP报文作为IP的数据,也就是放入IP报文格式的数据字段,IP报文格式如下图所示:

4位首部长度和16位总长度,4位首部长度不包括数据字段,并且单位是4字节。16位总长度包括数据字段,单位是1字节。

IP报文首部实现可以用下面的数据结构表示:


1

2

3

4

5

6

7

8

9

10

11

12

13

struct ip{

    unsigned char version:4;       // 版本

    unsigned char hlen:4;        // 首部长度

    unsigned char tos;             // 服务类型

    unsigned short len;         // 总长度

    unsigned short id;            // 标识符

    unsigned short offset;        // 标志和片偏移

    unsigned char ttl;            // 生存时间

    unsigned char protocol;     // 协议

    unsigned short checksum;    // 校验和

    struct in_addr ipsrc;        // 32位源ip地址

    struct in_addr ipdst;       // 32位目的ip地址

};

ICMP报文在发送给报文接收方时可能要经过若干子网,会牵涉到路由选择等问题,所以ICMP报文需通过IP协议来发送,是IP层的。

地址信息表示

地址信息包括:

1.地址族,基于IPv4的地址族还是IPv6的地址族。

2.IP地址。

3.端口号。

为了便于记录地址信息,系统定义了如下结构体:


1

2

3

4

5

6

struct sockaddr_in{

    sa_family_t        sin_family;     // 地址族

    uint16_t        sin_port;        // 端口号

    struct in_addr  sin_addr;          // 32位IP地址

    char             sin_zero[8];    // 不使用

};

其中struct in_addr结构体定义如下:


1

2

3

struct in_addr{

    in_addr_t     s_addr;        // 32位IP地址

};

in_addr_t使用如下宏指令定义,也就是无符号整型32位。


1

#define in_addr_t uint32_t

还有一种结构体也可以表示地址信息,如下所示:


1

2

3

4

struct sockaddr{

    sa_family_t    sin_family;     // 地址族

    char         sa_data[14]; // IP地址和端口

};

成员sa_data保存的信息包含IP地址和端口号,剩余部分填充0。

在网络编程中,常用的是struct sockaddr_in结构体,因为相对于struct sockaddr结构体,前者填充数据比较方便。

不过网络编程接口函数定义使用的是struct sockaddr结构体类型,这是由于最先使用的是struct sockaddr结构体,struct sockaddr_in结构体是后来为了方便填充地址信息数据定义。

上面两个结构体之间是可以相互转换的。定义地址信息时使用struct sockaddr_in结构体,然后将该结构体类型转为struct sockaddr结构体类型传递给网络编程接口函数即可。

主机字节序与网络字节序

在不同CPU中,4字节整型数值1在内存空间的保存方式是不同的。

4字节整型数值1可用二进制表示如下:

00000000 00000000 00000000 00000001

而有些CPU则以倒序保存。

00000001 00000000 00000000 00000000

所以,如果发送主机与接收主机CPU字节序不一样则就会出现问题。

引申上面的问题,这就涉及到CPU解析数据的方式,其方式有2种:

大端序(Big Endian):高位字节存放到低位地址。

小端序(Little Endian):高位字节存放到高位地址。由于不同CPU字节序不一样,因此,在通过网络传输数据时约定统一方式,这种约定称为网络字节序(Network Byte Order),非常简单——统一为大端序。

所以,进行网络传输数据前,需要先把数据数组转化为大端序格式再进行网络传输。接收到网络数据后,需要转换本机字节序格式然后进行后续处理。这些工作不需要我们自己完成,系统会自动转换的。

唯一需要转换的是向struct sockaddr_in结构体变量填充IP地址和端口号数据的时候。系统已经提供了一些函数,只需调用相应函数即可。

系统已经提供了一些函数,只需调用相应函数即可。


1

2

3

4

unsigned short htons(unsigned short);

unsigned short ntohs(unsigned short);

unsigned long  htonl(unsigned long);

unsigned long  ntohl(unsigned long);

htonl/htons中的h代表主机(host)字节序,n代表网络(network)字节序,s指的是short,l指的是long(需要注意一下,linux中long类型只占4个字节,跟int类型一样)。

用到的函数

gettimeofday()


1

2

#include <sys/time.h>

int gettimeofday(struct timeval *tv, struct timezone *tz);

该函数的作用是把当前的时间放入struct timeval结构体中返回。

注意:

1.精确级别,微妙级别

2.受系统时间修改影响

3.返回的秒数是从1970年1月1日0时0分0秒开始

其参数tv是保存获取时间结果的结构体,参数tz用于保存时区结果。

结构体timeval的定义为:


1

2

3

4

5

struct timeval

{

    long int tv_sec;      // 秒数

    long int tv_usec;     // 微秒数

}

结构体timezone的定义为:


1

2

3

4

5

struct timezone

{

    int tz_minuteswest;/*格林威治时间往西方的时差*/

    int tz_dsttime;    /*DST 时间的修正方式*/

}

timezone 参数若不使用则传入0即可,本项目传入0。

inet_addr


1

2

#include <arpa/inet.h>

in_addr_t inet_addr(const char *string);

该函数的作用是将用点分十进制字符串格式表示的IP地址转换成32位大端序整型。

成功时返回32位大端序整型数值,失败时返回INADDR_NONE。

inet_ntoa


1

char * inet_ntoa(struct in_addr addr);

该函数的作用与inet_addr正好相反。将32位大端序整型格式IP地址转换为点分十进制格式。

成功时返回转换的字符串地址值,失败时返回-1。

inet_addr函数在执行过程中,在内部会申请内存并保存结果字符串,然后返回内存地址。所以调用完该函数应该将字符串复制到其他内存空间。因为再次调用该函数时,之前保存的字符串很有可能被覆盖。

首先定义一个接收缓冲区char buf[20];,然后使用memcpy(buf, str1, sizeof(str))将inet_ntoa函数生成的字符串保存缓冲区。

gethostbyname


1

2

#include <netdb.h>

struct hostent * gethostbyname(const char * hostname);

该函数的作用是根据域名获取IP地址。

成功时返回hostent结构体地址,失败时返回NULL指针。

struct hosten结构体定义如下:


1

2

3

4

5

6

7

struct hostent{

    char *          h_name;

    char **     h_aliases;

    char         h_addrtype;

    char         h_length;

    char **     h_addr_list;

};

h_addr_list成员,它保存的就是域名对应IP地址。由于一个域名对应的IP地址不止一个,所以h_addr_list成员是char **类型,相当于二维字符数组。

host->h_addr_list[i]得到的是字符串指针,但该字符串指针实际指向的是struct in_addr结构体变量地址值。

(struct in_addr *)host->h_addr_list[i]将字符串指针转换为struct in_addr结构体指针。由于inet_ntoa参数类型是struct in_addr而不是struct in_addr *,所以用*运算符取出struct in_addr结构体的值。

socket


1

2

#include <sys/socket.h>

int socket(int family, int type, int protocol);

成功时返回文件描述符,失败时返回-1。

该函数的作用是创建一个套接字。一般为了执行网络I/O,一个进程必须做的第一件事就是调用socket函数。

第一个参数family:指明套接字中使用的协议族信息。

第二个参数type:指明套接口类型,也即套接字的数据传输方式。

在常见的使用socket进行网络编程中,经常使用SOCK_STREAM和SOCK_DGRAM,也就是TCP和UDP编程。

原始套接字的主要作用在三个方面:

1.通过原始套接字发送/接收ICMP协议包。

2.接收发向本级的,但TCP/IP协议栈不能处理的IP包。

3.用来发送一些自己制定源地址特殊作用的IP包(自己写IP头)。

ping命令使用的就是ICMP协议,因此我们不能直接通过建立一个SOCK_STREAM或SOCK_DGRAM来发送协议包,只能自己构建ICMP包通过SOCK_RAW来发送。

第三个参数protocol:指明协议类型。

参数protocol指明了所要接收的协议包。

如果指定了IPPROTO_ICMP,则内核碰到ip头中protocol域和创建socket所使用参数protocol相同的IP包,就会交给我们创建的原始套接字来处理。

因此,一般来说,要想接收什么样的数据包,就应该在参数protocol里来指定相应的协议。当内核向我们创建的原始套接字交付数据包的时候,是包括整个IP头的,并且是已经重组好的IP包。

这里的数据也就是前面所说的时间戳。

但是,当我们发送IP包的时候,却不用自己处理IP首部,IP首部由内核自己维护,首部中的协议字段被设置成调用socket函数时传递给它的第三个参数。

我们发送IP包时,发送数据时从IP首部的第一个字节开始的,所以只需要构造一个如下所示的数据缓冲区就可以了。

如果想自己处理IP首部,则需要设置IP_HDRINCL的socket选项,如下所示:


1

2

int flag = 1;

setsocketopt(sockfd, IPPROTO_TO, IP_HDRINCL, &flag, sizeof(int));

我们自己填充IP首部时,也不是填充IP首部的所有字段,而是应该将IP首部的id字段设置为0,表示让内核来处理这个字段。同时,内核还会自动完成IP首部的校验和的计算并填充。

recvfrom和sendto


1

2

3

4

#include <sys/socket.h>

ssize_t recvfrom(int sockfd, void * buff, size_t nbytes, int flags, struct sockaddr * from, socklen_t * addrlen);

ssize_t sendto(int sockfd, const void * buff, size_t nbytes, int flags,const struct sockaddr * to, socklen_t addrlen);

成功时返回读写的字节数,失败时返回-1。

sockfd参数:套接字描述符。

buff参数:指向读入或写出缓冲区的指针。

nbytes参数:读写字节数。

flags参数:本项目中设置为0。

recvfrom的from参数指向一个将由该函数在返回时填写数据发送者的地址信息的结构体,而该结构体中填写的字节数则放在addrlen参数所指的整数中。

sendto的to参数指向一个含有数据报接收者的地址信息的结构体,其大小由addrlen参数指定。

校验和算法

检验和算法在TCP/IP协议族中是比较常见的算法。IP、ICMP、UDP和TCP报文头部都有校验和字段,不过IP、TCP、UDP只针对首部计算校验和,而ICMP对首部和报文数据一起计算校验和。

检验和算法可以分成两步来实现。

首先在发送端,有以下三步: 1.把校验和字段置为0。

2.对需要校验的数据看成以16bit为单位的数字组成,依次进行二进制求和。

3.将上一步的求和结果取反,存入校验和字段。

其次在接收端,也有相应的三步:

1.对需要校验的数据看成以16bit为单位的数字组成,依次进行二进制求和,包括校验和字段。

2.将上一步的求和结果取反。

3.判断最终结果是否为0。如果为0,说明校验和正确。如果不为0,则协议栈会丢掉接收到的数据。

校验和算法就是二进制反码求和。由于先取反后相加与先相加后取反,得到的结果是一样的,所以上面的步骤都是先求和后取反。

实现校验和算法,代码如下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

/**

 * addr 指向需校验数据缓冲区的指针

 * len  需校验数据的总长度(字节单位)

 */

unsigned short checkSum(unsigned short *addr, int len){

    unsigned int sum = 0; 

    while(len > 1){

        sum += *addr++;

        len -= 2;

    }

    // 处理剩下的一个字节

    if(len == 1){

        sum += *(unsigned char *)addr;

    }

    // 将32位的高16位与低16位相加

    sum = (sum >> 16) + (sum & 0xffff);

    sum += (sum >> 16);

    return (unsigned short) ~sum;

}

首先定义了一个32位无符号整型的变量sum,用来保存16bit二进制数字相加的结果,由于16bit相加可能会产生进位,所以这里使用32位变量来保存结果,其中高16bit保存的是相加产生的进位。

然后下面的while循环,对数据按16bit累加求和。

接下来的if语句判断是否还剩下8bit(一字节)。如果校验的数据为奇数个字节,会剩下最后一字节。把最后一个字节视为一个2字节数据的高字节,这个2字节数据的低字节为0,继续累加。

之后的两行代码作用是将sum高16bit的值加到低16bit上,即把累加中最高位的进位加到最低位上。(sum >> 16)将高16bit右移到低16bit,(sum & 0xffff)将高16bit全部置为0。注意,这两步都不会改变sum原来的值。

进行了两次相加可以保证sum高16bit都为0,没有进位了。

最后取反,并返回。

使用反码计算校验和比较简单和快速。对于网络通信来说,最重要的就是效率和速度。

编码实现

第一步,首先创建原始套接字。

第二步,封装ICMP报文,向目的IP地址发送ICMP报文,1秒后接收ICMP响应报文,并打印TTL,RTT。

第三步:循环第二步N次,本项目设置为5。

第四步输出统计信息。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/time.h>

#include <arpa/inet.h>

#include <netdb.h>

#define ICMP_SIZE (sizeof(struct icmp))

#define ICMP_ECHO 8

#define ICMP_ECHOREPLY 0

#define BUF_SIZE 1024

#define NUM   5    // 发送报文次数

#define UCHAR  unsigned char

#define USHORT unsigned short

#define UINT   unsigned int

// ICMP报文数据结构

struct icmp{

    UCHAR           type;      // 类型

    UCHAR           code;      // 代码

    USHORT          checksum;  // 校验和

    USHORT          id;        // 标识符

    USHORT          sequence;  // 序号

    struct timeval  timestamp; // 时间戳

};

// IP首部数据结构

struct ip{

    // 主机字节序判断

    #if __BYTE_ORDER == __LITTLE_ENDIAN

    UCHAR   hlen:4;        // 首部长度

    UCHAR   version:4;     // 版本     

    #endif

    #if __BYTE_ORDER == __BIG_ENDIAN

    UCHAR   version:4;      

    UCHAR   hlen:4;   

    #endif   

    UCHAR   tos;             // 服务类型

    USHORT  len;             // 总长度

    USHORT  id;                // 标识符

    USHORT  offset;            // 标志和片偏移

    UCHAR   ttl;            // 生存时间

    UCHAR   protocol;       // 协议

    USHORT  checksum;       // 校验和

    struct in_addr ipsrc;    // 32位源ip地址

    struct in_addr ipdst;   // 32位目的ip地址

};

char buf[BUF_SIZE] = {0};

USHORT checkSum(USHORT *, int); // 计算校验和

float timediff(struct timeval *, struct timeval *); // 计算时间差

void pack(struct icmp *, int);  // 封装一个ICMP报文

int unpack(char *, int, char *);        // 对接收到的IP报文进行解包

int main(int argc, char * argv[]){

    struct hostent *host;

    struct icmp sendicmp;

    struct sockaddr_in from;

    struct sockaddr_in to;

    int fromlen = 0;

    int sockfd;

    int nsend = 0;

    int nreceived = 0;

    int i, n;

    in_addr_t inaddr;

    memset(&from, 0, sizeof(struct sockaddr_in));

    memset(&to, 0, sizeof(struct sockaddr_in));

    if(argc < 2){

        printf("use : %s hostname/IP address \n", argv[0]);

        exit(1);

    }

    // 生成原始套接字

    if((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1){

        printf("socket() error \n");

        exit(1);

    }

    // 设置目的地址信息

    to.sin_family = AF_INET;

    // 判断是域名还是ip地址

    if(inaddr = inet_addr(argv[1]) == INADDR_NONE){

        // 是域名

        if((host = gethostbyname(argv[1])) == NULL){

            printf("gethostbyname() error \n");

            exit(1);

        }

        to.sin_addr = *(struct in_addr *)host->h_addr_list[0];

    }else{

        // 是ip地址

        to.sin_addr.s_addr = inaddr;

    }

    // 输出域名ip地址信息

    printf("ping %s (%s) : %d bytes of data.\n", argv[1], inet_ntoa(to.sin_addr), (int)ICMP_SIZE);

    //循环发送报文、接收报文

    for(i = 0; i < NUM; i++){

        nsend++;  // 发送次数加1

        memset(&sendicmp, 0, ICMP_SIZE);

        pack(&sendicmp, nsend);

        // 发送报文

        if(sendto(sockfd, &sendicmp, ICMP_SIZE, 0, (struct sockaddr *)&to, sizeof(to)) == -1){

            printf("sendto() error \n");

            continue;

        }

        // 接收报文

        if((n = recvfrom(sockfd, buf, BUF_SIZE, 0, (struct sockaddr *)&from, &fromlen)) < 0){

            printf("recvform() error \n");

            continue;

        }

        nreceived++;  // 接收次数加1

        if(unpack(buf, n, inet_ntoa(from.sin_addr)) == -1){

            printf("unpack() error \n");

        }

        sleep(1);

    }

    // 输出统计信息

    printf("---  %s ping statistics ---\n", argv[1]);

    printf("%d packets transmitted, %d received, %%%d packet loss\n", nsend, nreceived,

            (nsend - nreceived) / nsend * 100);

    return 0;

}

/**

 * addr 指向需校验数据缓冲区的指针

 * len  需校验数据的总长度(字节单位)

 */

USHORT checkSum(USHORT *addr, int len){

    UINT sum = 0; 

    while(len > 1){

        sum += *addr++;

        len -= 2;

    }

    // 处理剩下的一个字节

    if(len == 1){

        sum += *(UCHAR *)addr;

    }

    // 将32位的高16位与低16位相加

    sum = (sum >> 16) + (sum & 0xffff);

    sum += (sum >> 16);

    return (USHORT) ~sum;

}

/**

 * 返回值单位:ms

 * begin 开始时间戳

 * end   结束时间戳

 */

float timediff(struct timeval *begin, struct timeval *end){

    int n;

    // 先计算两个时间点相差多少微秒

    n = ( end->tv_sec - begin->tv_sec ) * 1000000

        + ( end->tv_usec - begin->tv_usec );

    // 转化为毫秒返回

    return (float) (n / 1000);

}

/**

 * icmp 指向需要封装的ICMP报文结构体的指针

 * sequence 该报文的序号

 */

void pack(struct icmp * icmp, int sequence){

    icmp->type = ICMP_ECHO;

    icmp->code = 0;

    icmp->checksum = 0;

    icmp->id = getpid();

    icmp->sequence = sequence;

    gettimeofday(&icmp->timestamp, 0);

    icmp->checksum = checkSum((USHORT *)icmp, ICMP_SIZE);

}

/**

 * buf  指向接收到的IP报文缓冲区的指针

 * len  接收到的IP报文长度

 * addr 发送ICMP报文响应的主机IP地址

 */

int unpack(char * buf, int len, char * addr){

   int i, ipheadlen;

   struct ip * ip;

   struct icmp * icmp;

   float rtt;          // 记录往返时间

   struct timeval end; // 记录接收报文的时间戳

   ip = (struct ip *)buf;

   // 计算ip首部长度,即ip首部的长度标识乘4

   ipheadlen = ip->hlen << 2;

   // 越过ip首部,指向ICMP报文

   icmp = (struct icmp *)(buf + ipheadlen);

   // ICMP报文的总长度

   len -= ipheadlen;

   // 如果小于ICMP报文首部长度8

   if(len < 8){

        printf("ICMP packets\‘s length is less than 8 \n");

        return -1;

   }

   // 确保是我们所发的ICMP ECHO回应

   if(icmp->type != ICMP_ECHOREPLY ||

           icmp->id != getpid()){   

       printf("ICMP packets are not send by us \n");

       return -1;

   }

   // 计算往返时间

   gettimeofday(&end, 0);

   rtt = timediff(&icmp->timestamp, &end);

   // 打印ttl,rtt,seq

   printf("%d bytes from %s : icmp_seq=%u ttl=%d rtt=%fms \n",

           len, addr, icmp->sequence, ip->ttl, rtt);

   return 0;

}

时间: 2024-10-13 21:12:17

Ping命令的设计与实现的相关文章

docker run常用命令及 解决 ubuntu镜像无法识别 ifconfig ping 命令

docker run -it     docker 前端启动 container容器           -d             后端启动 container容器           -p             固定端口映射            -P             不固定端口映射           --name         给生成的容器起名字docker ps:默认显示正在运行的container       ps -a 显示所有的container容器docker r

Docker的ubuntu镜像安装的容器无ifconfig和ping命令的解决

Docker的Ubuntu镜像安装的容器无ifconfig命令和ping命令 解决: apt-get update apt install net-tools       # ifconfig apt install iputils-ping     # ping

[小菜随笔]python tkinter实现简单的ping命令

本文主要是介绍python图形界面上的按键与实际功能的对接,其实编程掌握了基础之后的学习应该都是靠自己去挖掘其他的 在网上发现多半教程都是2的,故本文使用的是python3.5,其实也没什么区别,就有一些支持库改变而已 首先我们使用python去编写一个简单的窗口程序,带一个按键,如下图 from tkinter import * #导入tk包 import os #导入os包,方便执行cmd命令,网上还有其他方法执行 test = Tk() #创建一个窗口程序 test.title('ping

Swift和C混合Socket编程实现简单的ping命令

这个是用Mac下的Network Utility工具实现ping命令,用Wireshark抓取的ICMP数据包: 发送ICMP数据包内容 接受ICMP数据包内容 一.icmp结构 要真正了解ping命令实现原理,就要了解ping命令所使用到的TCP/IP协议.ICMP(Internet Control Message,网际控制报文协议)是为网关和目标主机而提供的一种差错控制机制,使它们在遇到差错时能把错误报告给报文源发方.ICMP协议是IP层的 一个协议,但是由于差错报告在发送给报文源发方时可能

ping命令扫描局域网内的主机

linux: 禁ping vim /proc/sys/net/ipv4/icmp_echo_ignore_all 0 代表允许 1代表禁止 ping.sh #!/bin/bash for i in {2..5}; do   host=122.152.172.$i  ping -c2  $host  >/dev/null  if [ $? = 0 ]  then      echo "122.152.172.$i is connected"  else  echo "12

每天一个linux命令(54):ping命令

Linux系统的ping命令是常用的网络命令,它通常用来测试与目标主机的连通性,我们经常会说“ping一下某机器,看是不是开着”.不能打开网页时会说“你先ping网关地址192.168.1.1试试”.它通过发送ICMP ECHO_REQUEST数据包到网络主机(send ICMP ECHO_REQUEST to network hosts),并显示响应情况,这样我们就可以根据它输出的信息来确定目标主机是否可访问(但这不是绝对的).有些服务器为了防止通过ping探测到,通过防火墙设置了禁止ping

C#中的Ping命令

1.Ping命令基础知识 在网络中Ping 命令是一个十分好用的TCP/IP工具,它主要的功能是用来检测网络的连通情况和分析网络速度.我们可以用ping来给网络上指定IP的计算机发送一个数据包,而对方就要返回一个同样大小的数据包,根据返回的数据包就可以判定对方机器的存在. 在命令提示符中输入Ping /?,可以看到ping的所有参数: ping [-t] [-a] [-n count] [-l length] [-f] [-i ttl] [-v tos] [-r count] [-s count

Linux和Windows下ping命令详解

转:http://linux.chinaitlab.com/command/829332.html 一.Linux下的ping参数 用途 发送一个回送信号请求给网络主机. 语法 ping [ -d] [ -D ] [ -n ] [ -q ] [ -r] [ -v] [ \ -R ] [ -a addr_family ] [ -c Count ] [ -w timeout ] [ -f | -i \ Wait ] [ -l Preload ] [ -p Pattern ] [ -s PacketS

ssh命令、ping命令、traceroute 命令所使用的协议

在Node reboot or eviction: How to check if yourprivate interconnect CRS can transmit network heartbeats (文档 ID 1445075.1)中有这么一句话: The script in here performs the network connectivity check usingssh. This check complements ping or traceroute since ssh