导 读:PING 是一个用来检测网络连接速度的使用工具,下面的文章将介绍在C#中利用System.Net.Sockets 来创建一个自己的PING 工具。
--------------------------------------------------------------------------------
PING 是一个用来检测网络连接速度的工具,它会在本机和给出的远程主机名之间建立一个SOCKET 连接并向其发送一个ICMP协议格式的数据包,然后远程主机作出响应,发回一个数据包,通过计算发送到接收数据包的时间间隔,我们可以确定连接的速度。
使用方法 ping
1<hostname> [/r]
2
3<hostname> 主机名
4
5[/r] 可选属性,决定是否连续的 ping 远程主机。
6
7下面是代码:
8
9///ping.cs
10
11namespace SaurabhPing
12
13{
14
15using System;
16
17using System.Net;
18
19using System.Net.Sockets;
20
21/// <summary>
22
23/// 主要的类:ping
24
25/// </summary>
26
27class Ping
28
29{
30
31//声明几个常量
32
33const int SOCKET_ERROR = -1;
34
35const int ICMP_ECHO = 8;
36
37/// <summary>
38
39/// 这里取得Hostname参数
40
41/// </summary>
42
43public static void Main(string[] argv)
44
45{
46
47if(argv.Length==0)
48
49{
50
51//If user did not enter any Parameter inform him
52
53Console.WriteLine("Usage:Ping <hostname> /r") ;
54
55Console.WriteLine("<hostname> The name of the Host who you want to ping");
56
57Console.WriteLine("/r Ping the host continuously") ;
58
59}
60
61else if(argv.Length==1)
62
63{
64
65//Just the hostname provided by the user
66
67//call the method "PingHost" and pass the HostName as a parameter
68
69PingHost(argv[0]) ;
70
71}
72
73else if(argv.Length==2)
74
75{
76
77//the user provided the hostname and the switch
78
79if(argv[1]=="/r")
80
81{
82
83//loop the ping program
84
85while(true)
86
87{
88
89//call the method "PingHost" and pass the HostName as a parameter
90
91PingHost(argv[0]) ;
92
93}
94
95}
96
97else
98
99{
100
101//if the user provided some other switch
102
103PingHost(argv[0]) ;
104
105}
106
107}
108
109else
110
111{
112
113//Some error occurred
114
115Console.WriteLine("Error in Arguments") ;
116
117}
118
119}
120
121/// <summary>
122
123/// 主要的方法,用来取得IP,
124
125/// 并计算响应时间
126
127/// </summary>
128
129public static void PingHost(string host)
130
131{
132
133//Declare the IPHostEntry
134
135IPHostEntry serverHE, fromHE;
136
137int nBytes = 0;
138
139int dwStart = 0, dwStop = 0;
140
141//Initilize a Socket of the Type ICMP
142
143Socket socket =
144
145new Socket(AddressFamily.AfINet, SocketType.SockRaw, ProtocolType.ProtICMP);
146
147// Get the server endpoint
148
149try
150
151{
152
153serverHE = DNS.GetHostByName(host);
154
155}
156
157catch(Exception)
158
159{
160
161Console.WriteLine("Host not found"); // fail
162
163return ;
164
165}
166
167// Convert the server IP_EndPoint to an EndPoint
168
169IPEndPoint ipepServer = new IPEndPoint(serverHE.AddressList[0], 0);
170
171EndPoint epServer = (ipepServer);
172
173// Set the receiving endpoint to the client machine
174
175fromHE = DNS.GetHostByName(DNS.GetHostName());
176
177IPEndPoint ipEndPointFrom = new IPEndPoint(fromHE.AddressList[0], 0);
178
179EndPoint EndPointFrom = (ipEndPointFrom);
180
181int PacketSize = 0;
182
183IcmpPacket packet = new IcmpPacket();
184
185// Construct the packet to send
186
187packet.Type = ICMP_ECHO; //8
188
189packet.SubCode = 0;
190
191packet.CheckSum = UInt16.Parse("0");
192
193packet.Identifier = UInt16.Parse("45");
194
195packet.SequenceNumber = UInt16.Parse("0");
196
197int PingData = 32; // sizeof(IcmpPacket) - 8;
198
199packet.Data = new Byte[PingData];
200
201//Initilize the Packet.Data
202
203for (int i = 0; i < PingData; i++)
204
205{
206
207packet.Data[i] = (byte)'#';
208
209}
210
211//Variable to hold the total Packet size
212
213PacketSize = PingData + 8;
214
215Byte [] icmp_pkt_buffer = new Byte[ PacketSize ];
216
217Int32 Index = 0;
218
219//Call a Method Serialize which counts
220
221//The total number of Bytes in the Packet
222
223Index = Serialize(
224
225packet,
226
227icmp_pkt_buffer,
228
229PacketSize,
230
231PingData );
232
233//Error in Packet Size
234
235if( Index == -1 )
236
237{
238
239Console.WriteLine("Error in Making Packet");
240
241return ;
242
243}
244
245// now get this critter into a UInt16 array
246
247//Get the Half size of the Packet
248
249Double double_length = Convert.ToDouble(Index);
250
251Double dtemp = Math.Ceil( double_length / 2);
252
253int cksum_buffer_length = Convert.ToInt32(dtemp);
254
255//Create a Byte Array
256
257UInt16 [] cksum_buffer = new UInt16[cksum_buffer_length];
258
259//Code to initialize the Uint16 array
260
261int icmp_header_buffer_index = 0;
262
263for( int i = 0; i < cksum_buffer_length; i++ ) {
264
265cksum_buffer[i] =
266
267BitConverter.ToUInt16(icmp_pkt_buffer,icmp_header_buffer_index);
268
269icmp_header_buffer_index += 2;
270
271}
272
273//Call a method which will return a checksum
274
275UInt16 u_cksum = checksum(cksum_buffer, cksum_buffer_length);
276
277//Save the checksum to the Packet
278
279packet.CheckSum = u_cksum;
280
281// Now that we have the checksum, serialize the packet again
282
283Byte [] sendbuf = new Byte[ PacketSize ];
284
285//again check the packet size
286
287Index = Serialize(
288
289packet,
290
291sendbuf,
292
293PacketSize,
294
295PingData );
296
297//if there is a error report it
298
299if( Index == -1 )
300
301{
302
303Console.WriteLine("Error in Making Packet");
304
305return ;
306
307}
308
309dwStart = System.Environment.TickCount; // Start timing
310
311//send the Pack over the socket
312
313if ((nBytes = socket.SendTo(sendbuf, PacketSize, 0, epServer)) == SOCKET_ERROR)
314
315{
316
317Console.WriteLine("Socket Error cannot Send Packet");
318
319}
320
321// Initialize the buffers. The receive buffer is the size of the
322
323// ICMP header plus the IP header (20 bytes)
324
325Byte [] ReceiveBuffer = new Byte[256];
326
327nBytes = 0;
328
329//Receive the bytes
330
331bool recd =false ;
332
333int timeout=0 ;
334
335//loop for checking the time of the server responding
336
337while(!recd)
338
339{
340
341nBytes = socket.ReceiveFrom(ReceiveBuffer, 256, 0, ref EndPointFrom);
342
343if (nBytes == SOCKET_ERROR)
344
345{
346
347Console.WriteLine("Host not Responding") ;
348
349recd=true ;
350
351break;
352
353}
354
355else if(nBytes>0)
356
357{
358
359dwStop = System.Environment.TickCount - dwStart; // stop timing
360
361Console.WriteLine("Reply from "+epServer.ToString()+" in "
362
363+dwStop+"MS :Bytes Received"+nBytes);
364
365recd=true;
366
367break;
368
369}
370
371timeout=System.Environment.TickCount - dwStart;
372
373if(timeout>1000)
374
375{
376
377Console.WriteLine("Time Out") ;
378
379recd=true;
380
381}
382
383}
384
385//close the socket
386
387socket.Close();
388
389}
390
391/// <summary>
392
393/// This method get the Packet and calculates the total size
394
395/// of the Pack by converting it to byte array
396
397/// </summary>
398
399public static Int32 Serialize(IcmpPacket packet, Byte[] Buffer,
400
401Int32 PacketSize, Int32 PingData )
402
403{
404
405Int32 cbReturn = 0;
406
407// serialize the struct into the array
408
409int Index=0;
410
411Byte [] b_type = new Byte[1];
412
413b_type[0] = (packet.Type);
414
415Byte [] b_code = new Byte[1];
416
417b_code[0] = (packet.SubCode);
418
419Byte [] b_cksum = BitConverter.GetBytes(packet.CheckSum);
420
421Byte [] b_id = BitConverter.GetBytes(packet.Identifier);
422
423Byte [] b_seq = BitConverter.GetBytes(packet.SequenceNumber);
424
425// Console.WriteLine("Serialize type ");
426
427Array.Copy( b_type, 0, Buffer, Index, b_type.Length );
428
429Index += b_type.Length;
430
431// Console.WriteLine("Serialize code ");
432
433Array.Copy( b_code, 0, Buffer, Index, b_code.Length );
434
435Index += b_code.Length;
436
437// Console.WriteLine("Serialize cksum ");
438
439Array.Copy( b_cksum, 0, Buffer, Index, b_cksum.Length );
440
441Index += b_cksum.Length;
442
443// Console.WriteLine("Serialize id ");
444
445Array.Copy( b_id, 0, Buffer, Index, b_id.Length );
446
447Index += b_id.Length;
448
449Array.Copy( b_seq, 0, Buffer, Index, b_seq.Length );
450
451Index += b_seq.Length;
452
453// copy the data
454
455Array.Copy( packet.Data, 0, Buffer, Index, PingData );
456
457Index += PingData;
458
459if( Index != PacketSize/* sizeof(IcmpPacket) */) {
460
461cbReturn = -1;
462
463return cbReturn;
464
465}
466
467cbReturn = Index;
468
469return cbReturn;
470
471}
472
473/// <summary>
474
475/// This Method has the algorithm to make a checksum
476
477/// </summary>
478
479public static UInt16 checksum( UInt16[] buffer, int size )
480
481{
482
483Int32 cksum = 0;
484
485int counter;
486
487counter = 0;
488
489while ( size > 0 ) {
490
491UInt16 val = buffer[counter];
492
493cksum += Convert.ToInt32( buffer[counter] );
494
495counter += 1;
496
497size -= 1;
498
499}
500
501cksum = (cksum >> 16) + (cksum & 0xffff);
502
503cksum += (cksum >> 16);
504
505return (UInt16)(~cksum);
506
507}
508
509} // class ping
510
511/// <summary>
512
513/// Class that holds the Pack information
514
515/// </summary>
516
517public class IcmpPacket
518
519{
520
521public Byte Type; // type of message
522
523public Byte SubCode; // type of sub code
524
525public UInt16 CheckSum; // ones complement checksum of struct
526
527public UInt16 Identifier; // identifier
528
529public UInt16 SequenceNumber; // sequence number
530
531public Byte [] Data;
532
533} // class IcmpPacket
534
535}</hostname></hostname></hostname></hostname>