heh2007
04-02-2007, 09:04 AM
开发工具:VS2003 .NET FrameWork1.1
调用下列的SlpPing类的应用程序在Windows XP/2000中执行正常,但在Windows
Vista里总是出现远程节点无应答的错误(Debug时总出现<Request timed out.
m_sHostToPing:192.168.1.1>),为了能在Windows Vista中能执行,下列有关ICMP协议如何修改??
例:SlpPing slpPing = new SlpPing(“192.168.1.1”);
bool bSts = slpPing.PingHost();
/// <summary>
/// Class that ping the specified host
/// </summary>
public class SlpPing
{
/// <summary>
/// Constructor
/// </summary>
public SlpPing(string strHostToPing)
{
m_sHostToPing = strHostToPing;
}
//Declare some Constant Variables
private const int SOCKET_ERROR = -1;
private const int ICMP_ECHO = 8;
private const int ICMP_PACKDATA_SIZE = 32;
private const int MAX_PACKET_SIZE = 65535;
private string m_sHostToPing; // Host to ping
private const int nPingTimeout = 1000; // Timeout
private int nPingCount = 1; // Ping count
private long lngPacketsSent = 0;
private long lngPacketsReceived = 0;
public bool PingHost()
{
bool bSts = false;
int nBytesReceived = 0;
int nStart = 0, nStop = 0;
int nLoop = 0;
int iResult = 0;
int iPacketSize = ICMP_PACKDATA_SIZE + 8;
long lngTotalTransmitTime = 0;
try
{
byte[] byteSendBuffer = new byte[iPacketSize];
// Construct the packet to send
bSts = DoIcmpPacketData(byteSendBuffer);
IPAddress hostadd = IPAddress.Parse(m_sHostToPing);
EndPoint epServer = new IPEndPoint(hostadd, 0);
IPHostEntry pingSource = Dns.GetHostByName(Dns.GetHostName());
EndPoint endPointFrom = new IPEndPoint(pingSource.AddressList[0],0);
Debug.WriteLine(string.Format("\nPinging {0} [{1}] with {2} bytes of
data:\n", m_sHostToPing,
((IPEndPoint)epServer).Address.ToString(), ICMP_PACKDATA_SIZE));
//Loop the ping
int nMinTransmitTime = int.MaxValue, nMaxTransmitTime = int.MinValue;
do
{
bool bReceived = false ;
//Initialize a Socket of the Type ICMP
Socket pingSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Raw, ProtocolType.Icmp);
//Set socket timeout, but this doesn't seem to work...
pingSocket.SetSocketOption( SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout, (int) nPingTimeout);
pingSocket.SetSocketOption( SocketOptionLevel.Socket,
SocketOptionName.SendTimeout, (int) nPingTimeout);
// Initialize the buffers. The receive buffer is the size of the
// ICMP header plus the IP header (20 bytes)
byte [] ReceiveBuffer = new byte[MAX_PACKET_SIZE];
nStart = System.Environment.TickCount; // Start timing
//Gather stats
lngPacketsSent ++;
//send the Pack over the socket
iResult = pingSocket.SendTo(byteSendBuffer, iPacketSize,
SocketFlags.None , epServer);
Debug.WriteLine (string.Format("Send to {0}
m_sHostToPing:{1}",((IPEndPoint)epServer).Address.ToString(), m_sHostToPing));
if ((iResult) == SOCKET_ERROR)
{
//Debug.WriteLine("Socket Error cannot Send Packet");
}
//Receive the bytes
nBytesReceived = 0;
//loop while waiting checking the time of the server responding
while(!bReceived)
{
try
{
nBytesReceived = pingSocket.ReceiveFrom(ReceiveBuffer,
MAX_PACKET_SIZE, SocketFlags.None, ref endPointFrom);
}
catch
{
Debug.WriteLine (string.Format("Request timed out.
m_sHostToPing:{0}", m_sHostToPing));
bReceived = false;
break;
}
if (nBytesReceived == SOCKET_ERROR)
{
Debug.WriteLine(string.Format("Host not Responding.
m_sHostToPing:{0}", m_sHostToPing));
bReceived = false;
break;
}
else if (nBytesReceived > 0)
{
if (((IPEndPoint)endPointFrom).Address.ToString() == m_sHostToPing)
{
bReceived = true;
nStop = System.Environment.TickCount - nStart; // stop timing
//Check for timeout
if ( nStop > nPingTimeout)
{
Debug.WriteLine (string.Format("Request timed out.
m_sHostToPing:{0}", m_sHostToPing));
bReceived = false;
System.Threading.Thread.Sleep(System.TimeSpan.FromMilliseconds(1000));
break;
}
if (nStop < 10)
{
Debug.WriteLine(string.Format("Reply from {0}: bytes: {1}
time:<10ms m_sHostToPing:{2}", ((IPEndPoint)endPointFrom).Address.ToString(),
nBytesReceived - 28, m_sHostToPing));
}
else
{
Debug.WriteLine(string.Format("Reply from {0}: bytes: {1} time:
{2}ms m_sHostToPing:{3}", ((IPEndPoint)endPointFrom).Address.ToString(),
nBytesReceived - 28, nStop, m_sHostToPing));
}
nPingCount = 1;
break;
}
else
{ //If received data from other host, dispose it.
//Debug.WriteLine(string.Format("Reply from {0}: bytes: {1}
time:<10ms m_sHostToPing:{2}", ((IPEndPoint)endPointFrom).Address.ToString(),
nBytesReceived - 28, m_sHostToPing));
bReceived = false;
}
}
}//while
//Gather stats
if (bReceived)
{
lngPacketsReceived++;
lngTotalTransmitTime += nStop;
if (nStop > nMaxTransmitTime) nMaxTransmitTime = nStop;
if (nStop < nMinTransmitTime) nMinTransmitTime = nStop;
}
nLoop++;
if (bReceived && nLoop < nPingCount) //not last ping
{
System.Threading.Thread.Sleep(System.TimeSpan.FromMilliseconds(1000));
}
//close the socket
pingSocket.Shutdown(SocketShutdown.Both);
pingSocket.Close();
} while (nLoop < nPingCount); //Do
}
catch
{
lngPacketsSent = -1;
}
return (lngPacketsSent == lngPacketsReceived);
}
/// <summary>
/// This method is used to construct the packet to send
/// </summary>
private static bool DoIcmpPacketData(byte[] byteSendBuffer)
{
bool bSts = false;
int nPacketSize = 0;
IcmpPacket PingPacket = new IcmpPacket();
// Construct the packet to send
PingPacket.Type = ICMP_ECHO; //8
PingPacket.SubCode = 0;
PingPacket.CheckSum = UInt16.Parse("0");
PingPacket.Identifier = UInt16.Parse("45");
PingPacket.SequenceNumber = UInt16.Parse("0");
PingPacket.Data = new Byte[ICMP_PACKDATA_SIZE];
//Initialize the Packet.Data
for (int nCount = 0; nCount < ICMP_PACKDATA_SIZE; nCount++)
{
PingPacket.Data[nCount] = (byte)'#';
}
//Variable to hold the total Packet size
nPacketSize = ICMP_PACKDATA_SIZE + 8;
byte [] bytPktBuffer = new byte[nPacketSize];
int nResult = 0;
//Call a Method Serialize which counts
//The total number of Bytes in the Packet
nResult = Serialize(PingPacket, bytPktBuffer, nPacketSize,
ICMP_PACKDATA_SIZE );
//Error in Packet Size
if( nResult == -1 )
{
//Debug.WriteLine("Error in Making Packet");
return bSts;
}
// now get this critter into a ushort array
ushort [] cksum_buffer = new ushort[Convert.ToInt32( Math.Ceiling(
Convert.ToDouble(nResult) / 2))];
//Code to initialize the ushort array
int ncmp_header_buffer_index = 0;
for( int nCount = 0; nCount < cksum_buffer.Length; nCount++ )
{
cksum_buffer[nCount] = BitConverter.ToUInt16(bytPktBuffer,
ncmp_header_buffer_index);
ncmp_header_buffer_index += 2;
}
//Call a method which will return a checksum
//Save the checksum to the Packet
PingPacket.CheckSum = CheckSum(cksum_buffer);
// Now that we have the checksum, serialize the packet again
nResult = Serialize(PingPacket, byteSendBuffer, nPacketSize,
ICMP_PACKDATA_SIZE );
//if there is a error report it
if( nResult == -1 )
{
//Debug.WriteLine("Error in Making Packet");
return bSts;
}
bSts = true;
return bSts;
}
/// <summary>
/// This method is used to get the Packet and calculates the total size
/// of the Pack by converting it to byte array
/// </summary>
private static int Serialize(IcmpPacket ThisPacket, byte[] Buffer, int
PacketSize, int PingData )
{
int nReturn = 0;
// serialize the struct into the array
int nIndex = 0;
byte [] b_type = new byte[1];
b_type[0] = ThisPacket.Type;
byte [] b_code = new byte[1];
b_code[0] = ThisPacket.SubCode;
byte [] b_cksum = BitConverter.GetBytes(ThisPacket.CheckSum);
byte [] b_id = BitConverter.GetBytes(ThisPacket.Identifier);
byte [] b_seq = BitConverter.GetBytes(ThisPacket.SequenceNumber);
// Debug.WriteLine("Serialize type ");
Array.Copy( b_type, 0, Buffer, nIndex, b_type.Length );
nIndex += b_type.Length;
// Debug.WriteLine("Serialize code ");
Array.Copy( b_code, 0, Buffer, nIndex, b_code.Length );
nIndex += b_code.Length;
// Debug.WriteLine("Serialize cksum ");
Array.Copy( b_cksum, 0, Buffer, nIndex, b_cksum.Length );
nIndex += b_cksum.Length;
// Debug.WriteLine("Serialize id ");
Array.Copy( b_id, 0, Buffer, nIndex, b_id.Length );
nIndex += b_id.Length;
Array.Copy( b_seq, 0, Buffer, nIndex, b_seq.Length );
nIndex += b_seq.Length;
// copy the data
Array.Copy( ThisPacket.Data, 0, Buffer, nIndex, PingData );
nIndex += PingData;
if( nIndex != PacketSize/* sizeof(IcmpPacket) */)
{
nReturn = -1;
return nReturn;
}
nReturn = nIndex;
return nReturn;
}
/// <summary>
/// Checksum -
/// Algorithm to create a checksup for a buffer
/// </summary>
private static ushort CheckSum( ushort[] BufferToChecksum )
{
int nCheckSum = 0;
for (uint nCount = 0; nCount < BufferToChecksum.Length; nCount++)
{
nCheckSum += Convert.ToInt32( BufferToChecksum[nCount] );
}
nCheckSum = (nCheckSum >> 16) + (nCheckSum & 0xffff);
nCheckSum += (nCheckSum >> 16);
return (ushort)(~nCheckSum);
}
/// <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 ushort CheckSum; // ones complement checksum of struct
public ushort Identifier; // identifier
public ushort SequenceNumber; // sequence number
public byte[] Data; // byte array of data
} // class IcmpPacket
}
调用下列的SlpPing类的应用程序在Windows XP/2000中执行正常,但在Windows
Vista里总是出现远程节点无应答的错误(Debug时总出现<Request timed out.
m_sHostToPing:192.168.1.1>),为了能在Windows Vista中能执行,下列有关ICMP协议如何修改??
例:SlpPing slpPing = new SlpPing(“192.168.1.1”);
bool bSts = slpPing.PingHost();
/// <summary>
/// Class that ping the specified host
/// </summary>
public class SlpPing
{
/// <summary>
/// Constructor
/// </summary>
public SlpPing(string strHostToPing)
{
m_sHostToPing = strHostToPing;
}
//Declare some Constant Variables
private const int SOCKET_ERROR = -1;
private const int ICMP_ECHO = 8;
private const int ICMP_PACKDATA_SIZE = 32;
private const int MAX_PACKET_SIZE = 65535;
private string m_sHostToPing; // Host to ping
private const int nPingTimeout = 1000; // Timeout
private int nPingCount = 1; // Ping count
private long lngPacketsSent = 0;
private long lngPacketsReceived = 0;
public bool PingHost()
{
bool bSts = false;
int nBytesReceived = 0;
int nStart = 0, nStop = 0;
int nLoop = 0;
int iResult = 0;
int iPacketSize = ICMP_PACKDATA_SIZE + 8;
long lngTotalTransmitTime = 0;
try
{
byte[] byteSendBuffer = new byte[iPacketSize];
// Construct the packet to send
bSts = DoIcmpPacketData(byteSendBuffer);
IPAddress hostadd = IPAddress.Parse(m_sHostToPing);
EndPoint epServer = new IPEndPoint(hostadd, 0);
IPHostEntry pingSource = Dns.GetHostByName(Dns.GetHostName());
EndPoint endPointFrom = new IPEndPoint(pingSource.AddressList[0],0);
Debug.WriteLine(string.Format("\nPinging {0} [{1}] with {2} bytes of
data:\n", m_sHostToPing,
((IPEndPoint)epServer).Address.ToString(), ICMP_PACKDATA_SIZE));
//Loop the ping
int nMinTransmitTime = int.MaxValue, nMaxTransmitTime = int.MinValue;
do
{
bool bReceived = false ;
//Initialize a Socket of the Type ICMP
Socket pingSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Raw, ProtocolType.Icmp);
//Set socket timeout, but this doesn't seem to work...
pingSocket.SetSocketOption( SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout, (int) nPingTimeout);
pingSocket.SetSocketOption( SocketOptionLevel.Socket,
SocketOptionName.SendTimeout, (int) nPingTimeout);
// Initialize the buffers. The receive buffer is the size of the
// ICMP header plus the IP header (20 bytes)
byte [] ReceiveBuffer = new byte[MAX_PACKET_SIZE];
nStart = System.Environment.TickCount; // Start timing
//Gather stats
lngPacketsSent ++;
//send the Pack over the socket
iResult = pingSocket.SendTo(byteSendBuffer, iPacketSize,
SocketFlags.None , epServer);
Debug.WriteLine (string.Format("Send to {0}
m_sHostToPing:{1}",((IPEndPoint)epServer).Address.ToString(), m_sHostToPing));
if ((iResult) == SOCKET_ERROR)
{
//Debug.WriteLine("Socket Error cannot Send Packet");
}
//Receive the bytes
nBytesReceived = 0;
//loop while waiting checking the time of the server responding
while(!bReceived)
{
try
{
nBytesReceived = pingSocket.ReceiveFrom(ReceiveBuffer,
MAX_PACKET_SIZE, SocketFlags.None, ref endPointFrom);
}
catch
{
Debug.WriteLine (string.Format("Request timed out.
m_sHostToPing:{0}", m_sHostToPing));
bReceived = false;
break;
}
if (nBytesReceived == SOCKET_ERROR)
{
Debug.WriteLine(string.Format("Host not Responding.
m_sHostToPing:{0}", m_sHostToPing));
bReceived = false;
break;
}
else if (nBytesReceived > 0)
{
if (((IPEndPoint)endPointFrom).Address.ToString() == m_sHostToPing)
{
bReceived = true;
nStop = System.Environment.TickCount - nStart; // stop timing
//Check for timeout
if ( nStop > nPingTimeout)
{
Debug.WriteLine (string.Format("Request timed out.
m_sHostToPing:{0}", m_sHostToPing));
bReceived = false;
System.Threading.Thread.Sleep(System.TimeSpan.FromMilliseconds(1000));
break;
}
if (nStop < 10)
{
Debug.WriteLine(string.Format("Reply from {0}: bytes: {1}
time:<10ms m_sHostToPing:{2}", ((IPEndPoint)endPointFrom).Address.ToString(),
nBytesReceived - 28, m_sHostToPing));
}
else
{
Debug.WriteLine(string.Format("Reply from {0}: bytes: {1} time:
{2}ms m_sHostToPing:{3}", ((IPEndPoint)endPointFrom).Address.ToString(),
nBytesReceived - 28, nStop, m_sHostToPing));
}
nPingCount = 1;
break;
}
else
{ //If received data from other host, dispose it.
//Debug.WriteLine(string.Format("Reply from {0}: bytes: {1}
time:<10ms m_sHostToPing:{2}", ((IPEndPoint)endPointFrom).Address.ToString(),
nBytesReceived - 28, m_sHostToPing));
bReceived = false;
}
}
}//while
//Gather stats
if (bReceived)
{
lngPacketsReceived++;
lngTotalTransmitTime += nStop;
if (nStop > nMaxTransmitTime) nMaxTransmitTime = nStop;
if (nStop < nMinTransmitTime) nMinTransmitTime = nStop;
}
nLoop++;
if (bReceived && nLoop < nPingCount) //not last ping
{
System.Threading.Thread.Sleep(System.TimeSpan.FromMilliseconds(1000));
}
//close the socket
pingSocket.Shutdown(SocketShutdown.Both);
pingSocket.Close();
} while (nLoop < nPingCount); //Do
}
catch
{
lngPacketsSent = -1;
}
return (lngPacketsSent == lngPacketsReceived);
}
/// <summary>
/// This method is used to construct the packet to send
/// </summary>
private static bool DoIcmpPacketData(byte[] byteSendBuffer)
{
bool bSts = false;
int nPacketSize = 0;
IcmpPacket PingPacket = new IcmpPacket();
// Construct the packet to send
PingPacket.Type = ICMP_ECHO; //8
PingPacket.SubCode = 0;
PingPacket.CheckSum = UInt16.Parse("0");
PingPacket.Identifier = UInt16.Parse("45");
PingPacket.SequenceNumber = UInt16.Parse("0");
PingPacket.Data = new Byte[ICMP_PACKDATA_SIZE];
//Initialize the Packet.Data
for (int nCount = 0; nCount < ICMP_PACKDATA_SIZE; nCount++)
{
PingPacket.Data[nCount] = (byte)'#';
}
//Variable to hold the total Packet size
nPacketSize = ICMP_PACKDATA_SIZE + 8;
byte [] bytPktBuffer = new byte[nPacketSize];
int nResult = 0;
//Call a Method Serialize which counts
//The total number of Bytes in the Packet
nResult = Serialize(PingPacket, bytPktBuffer, nPacketSize,
ICMP_PACKDATA_SIZE );
//Error in Packet Size
if( nResult == -1 )
{
//Debug.WriteLine("Error in Making Packet");
return bSts;
}
// now get this critter into a ushort array
ushort [] cksum_buffer = new ushort[Convert.ToInt32( Math.Ceiling(
Convert.ToDouble(nResult) / 2))];
//Code to initialize the ushort array
int ncmp_header_buffer_index = 0;
for( int nCount = 0; nCount < cksum_buffer.Length; nCount++ )
{
cksum_buffer[nCount] = BitConverter.ToUInt16(bytPktBuffer,
ncmp_header_buffer_index);
ncmp_header_buffer_index += 2;
}
//Call a method which will return a checksum
//Save the checksum to the Packet
PingPacket.CheckSum = CheckSum(cksum_buffer);
// Now that we have the checksum, serialize the packet again
nResult = Serialize(PingPacket, byteSendBuffer, nPacketSize,
ICMP_PACKDATA_SIZE );
//if there is a error report it
if( nResult == -1 )
{
//Debug.WriteLine("Error in Making Packet");
return bSts;
}
bSts = true;
return bSts;
}
/// <summary>
/// This method is used to get the Packet and calculates the total size
/// of the Pack by converting it to byte array
/// </summary>
private static int Serialize(IcmpPacket ThisPacket, byte[] Buffer, int
PacketSize, int PingData )
{
int nReturn = 0;
// serialize the struct into the array
int nIndex = 0;
byte [] b_type = new byte[1];
b_type[0] = ThisPacket.Type;
byte [] b_code = new byte[1];
b_code[0] = ThisPacket.SubCode;
byte [] b_cksum = BitConverter.GetBytes(ThisPacket.CheckSum);
byte [] b_id = BitConverter.GetBytes(ThisPacket.Identifier);
byte [] b_seq = BitConverter.GetBytes(ThisPacket.SequenceNumber);
// Debug.WriteLine("Serialize type ");
Array.Copy( b_type, 0, Buffer, nIndex, b_type.Length );
nIndex += b_type.Length;
// Debug.WriteLine("Serialize code ");
Array.Copy( b_code, 0, Buffer, nIndex, b_code.Length );
nIndex += b_code.Length;
// Debug.WriteLine("Serialize cksum ");
Array.Copy( b_cksum, 0, Buffer, nIndex, b_cksum.Length );
nIndex += b_cksum.Length;
// Debug.WriteLine("Serialize id ");
Array.Copy( b_id, 0, Buffer, nIndex, b_id.Length );
nIndex += b_id.Length;
Array.Copy( b_seq, 0, Buffer, nIndex, b_seq.Length );
nIndex += b_seq.Length;
// copy the data
Array.Copy( ThisPacket.Data, 0, Buffer, nIndex, PingData );
nIndex += PingData;
if( nIndex != PacketSize/* sizeof(IcmpPacket) */)
{
nReturn = -1;
return nReturn;
}
nReturn = nIndex;
return nReturn;
}
/// <summary>
/// Checksum -
/// Algorithm to create a checksup for a buffer
/// </summary>
private static ushort CheckSum( ushort[] BufferToChecksum )
{
int nCheckSum = 0;
for (uint nCount = 0; nCount < BufferToChecksum.Length; nCount++)
{
nCheckSum += Convert.ToInt32( BufferToChecksum[nCount] );
}
nCheckSum = (nCheckSum >> 16) + (nCheckSum & 0xffff);
nCheckSum += (nCheckSum >> 16);
return (ushort)(~nCheckSum);
}
/// <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 ushort CheckSum; // ones complement checksum of struct
public ushort Identifier; // identifier
public ushort SequenceNumber; // sequence number
public byte[] Data; // byte array of data
} // class IcmpPacket
}