Nutzername  
Kennwort
 
     
  C# - Ping Utility und TimeOut Multithreading  
       
 
Im Februar 2001 veröffentlichte Lance Olson einen Artikel zum Thema "Writing Peer-to-Peer Networked Apps with the Microsoft .NET Framework", der unter anderem auf den MSDN Seiten nachzulesen ist. Der zur Verfügung gestellte Quellcode enthielt ein Klasse, mit der es möglich war, ICMP-Pakete (Ping) an beliebige Hosts zu senden. Da der Code noch auf der Beta1-Version des .NET Framework aufsetzte, passte Peter A. Bromberg die Ping-Implementierung den geänderten Framework-Klassen der finalen Version an.
Bei der Verwendung der Klasse von Peter wurden 2 Probleme beobachtet, die in dem hier veröffentlichten Quellcode behoben worden sind.

  • Problem 1: Wird in der Methode checksum() die Prüfung auf mathematischen Überlauf aktiviert, so kommt es bei einer Typkonvertierung zu einer Exception.
  • Problem 2: Sind im Windows-System Einträge in der hosts-Datei vorhanden und werden diese hosts angepingt, so kommt es zu einem Deadlock, wenn die entsprechenden Maschinen down sind.
Problem 1 wurde durch die Umstellung der Konvertierung von dezimal auf hexadezimal gelöst. Bei Problem 2 wurde die Klasse Ping entsprechend den Anforderungen an Multithreading abgeändert. Der Ping-Thread endet definitiv nach einem festzulegenden TimeOut, wodurch ein eventueller Deadlock unterbrochen wird.
 
Download Ping Utility
 
Konsolenanwendung zum Test der Ping - Klasse
using System;
using System.Threading;
using Teserco.Net.Sockets;

namespace Teserco.Test
{

class PingTest
{
	[STAThread]
	static void Main(string[] args)
	{
		Ping p = new Ping();
		//Host name or IP address
		p.Host = "localhost";
		//TimeOut [ms]
		int timeOut = 100; 
	
		Thread pingThread = new Thread(new ThreadStart(p.PingHost));
		pingThread.IsBackground = true;
		pingThread.Priority = ThreadPriority.Highest;
		pingThread.Start();
		pingThread.Join(timeOut);
			
		//Message from Ping class
		Console.WriteLine(p.PingResponse);
		Console.ReadLine();
	}
}

}
 
Ping - Klasse
using System;
using System.Net;
using System.Net.Sockets;
namespace Teserco.Net.Sockets {
/// <summary> /// The Main Ping Class /// </summary> public class Ping { private string _host; private string _pingResponse;
public Ping() { this._pingResponse = "Host not found"; }
public string Host { set { this._host = value; } }
public string PingResponse { get { return this._pingResponse; } }
//Declare some Constant Variables const int SOCKET_ERROR = -1; const int ICMP_ECHO = 8;
/// <summary> /// This public method takes the "hostname" of the server /// and then it pings it and shows the response time /// Data is returned as a string. IP addresses are resolved. /// </summary>
public void PingHost() { //Declare the IPHostEntry IPHostEntry serverHE, fromHE; int nBytes = 0; int dwStart = 0, dwStop = 0; //Initialize a Socket of the Type ICMP Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp); socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000);
// Get the server endpoint try { serverHE = Dns.GetHostByName(this._host); } catch(Exception) { // fail this._pingResponse = "Host not found"; return; }
// Convert the server IP_EndPoint to an EndPoint IPEndPoint ipepServer = new IPEndPoint( serverHE.AddressList[0], 0); EndPoint epServer = (ipepServer);
// Set the receiving endpoint to the client machine fromHE = Dns.GetHostByName(Dns.GetHostName()); IPEndPoint ipEndPointFrom = new IPEndPoint( fromHE.AddressList[0], 0); EndPoint EndPointFrom = (ipEndPointFrom);
int PacketSize = 0; IcmpPacket packet = new IcmpPacket(); // Construct the packet to send packet.Type = ICMP_ECHO; //8 packet.SubCode = 0; packet.CheckSum = UInt16.Parse("0"); packet.Identifier = UInt16.Parse("45"); packet.SequenceNumber = UInt16.Parse("0"); int PingData = 32; // sizeof(IcmpPacket) - 8; packet.Data = new Byte[PingData]; //Initilize the Packet.Data for(int i = 0; i < PingData; i++) { packet.Data[i] = (byte)'#'; }
//Variable to hold the total Packet size PacketSize = PingData + 8; Byte [] icmp_pkt_buffer = new Byte[PacketSize]; Int32 Index = 0; //Call a Method Serialize which counts //The total number of Bytes in the Packet Index = Serialize(packet, icmp_pkt_buffer, PacketSize, PingData); //Error in Packet Size if(Index == -1) { this._pingResponse = "Error Creating Packet"; return; }
// convert into a Int32 array
//Get the Half size of the Packet
Double double_length = Convert.ToDouble(Index); Double dtemp = Math.Ceiling( double_length / 2); int cksum_buffer_length = Convert.ToInt32(dtemp); //Create a Byte Array UInt16 [] cksum_buffer = new UInt16[cksum_buffer_length]; //Code to initialize the Int32 array int icmp_header_buffer_index = 0; for(int i = 0; i < cksum_buffer_length; i++) { cksum_buffer[i] = BitConverter.ToUInt16( icmp_pkt_buffer, icmp_header_buffer_index); icmp_header_buffer_index += 2; }
//Call a method which will return a checksum UInt16 u_cksum = checksum(cksum_buffer, cksum_buffer_length);
//Save the checksum to the Packet packet.CheckSum = u_cksum;
//Now that we have the checksum, serialize the packet again Byte [] sendbuf = new Byte[ PacketSize ];
//again check the packet size
Index = Serialize(packet, sendbuf, PacketSize, PingData);
//if there is a error report it if(Index == -1) { this._pingResponse = "Error Creating Packet"; return; }
dwStart = System.Environment.TickCount; // Start timing if((nBytes = socket.SendTo(sendbuf, PacketSize, 0, epServer)) == SOCKET_ERROR) { this._pingResponse = "Socket Error: cannot send Packet"; return; }
// Initialize the buffers. The receive buffer is the size of the // ICMP header plus the IP header (20 bytes) Byte [] ReceiveBuffer = new Byte[256]; nBytes = 0;
//Receive the bytes bool recd = false; int timeout=0;
//loop for checking the time of the server responding while(!recd) { nBytes = socket.ReceiveFrom(ReceiveBuffer, 256, 0, ref EndPointFrom);
if(nBytes == SOCKET_ERROR) { this._pingResponse = "Host not Responding"; return; } else if(nBytes>0) { // stop timing dwStop = System.Environment.TickCount - dwStart; this._pingResponse = "Reply from " + epServer.ToString() + " in " + dwStop + "ms. Received: " + nBytes + " Bytes."; return; }
timeout=System.Environment.TickCount - dwStart; if(timeout>1000) { this._pingResponse = "Time Out"; return; } }
//close the socket socket.Close(); this._pingResponse = string.Empty; return; }
/// <summary> /// This method get the Packet and calculates the total size /// of the Pack by converting it to byte array /// </summary> public static Int32 Serialize(IcmpPacket packet, Byte[] Buffer, Int32 PacketSize, Int32 PingData) { Int32 cbReturn = 0; // serialize the struct into the array int Index = 0;
Byte [] b_type = new Byte[1]; b_type[0] = (packet.Type);
Byte [] b_code = new Byte[1]; b_code[0] = (packet.SubCode);
Byte [] b_cksum = BitConverter.GetBytes(packet.CheckSum); Byte [] b_id = BitConverter.GetBytes(packet.Identifier); Byte [] b_seq = BitConverter.GetBytes(packet.SequenceNumber);
// Console.WriteLine("Serialize type "); Array.Copy( b_type, 0, Buffer, Index, b_type.Length); Index += b_type.Length;
// Console.WriteLine("Serialize code "); Array.Copy( b_code, 0, Buffer, Index, b_code.Length); Index += b_code.Length;
// Console.WriteLine("Serialize cksum "); Array.Copy( b_cksum, 0, Buffer, Index, b_cksum.Length); Index += b_cksum.Length;
// Console.WriteLine("Serialize id "); Array.Copy( b_id, 0, Buffer, Index, b_id.Length); Index += b_id.Length;
Array.Copy( b_seq, 0, Buffer, Index, b_seq.Length); Index += b_seq.Length;
// copy the data Array.Copy( packet.Data, 0, Buffer, Index, PingData);
Index += PingData;
if(Index != PacketSize/* sizeof(IcmpPacket) */) { cbReturn = -1; return cbReturn; }
cbReturn = Index; return cbReturn;
}
/// <summary> /// This Method has the algorithm to make a checksum /// </summary> public static UInt16 checksum(UInt16[] buffer, int size) { Int32 cksum = 0; int counter; counter = 0;
while (size > 0) { Int32 val = buffer[counter]; cksum += Convert.ToInt32(buffer[counter]); counter += 1; size -= 1; }
cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >> 16);
string cksumHex = Convert.ToString(~cksum, 16); string cksumHexConverted = cksumHex.Substring( cksumHex.Length - 4, 4); return Convert.ToUInt16(cksumHexConverted, 16); } }
/// <summary> /// Class that holds the Pack information /// </summary> public class IcmpPacket { public Byte Type; // type of message public Byte SubCode; // type of sub code public UInt16 CheckSum; // ones complement checksum of struct public UInt16 Identifier; // identifier public UInt16 SequenceNumber; // sequence number public Byte [] Data; } }
 
 
Copyright © teserco 2004