Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Programando Un Puñetero Ping En C#

Iniciado por synchrnzr, 09 de Noviembre de 2004, 10:22:42 AM

« anterior - próximo »

synchrnzr

 Holaaaa

Estoy haciendo una aplicación estúpida en C# que consiste en pingear una serie de IPs para comprobar que ordenadores están encendidos y tienen conexión en la red de donde curro. El caso es que por más que especifico que el socket del ping no sea bloqueante, el puñetero thread se me bloquea hasta recibir respuesta (respuesta que puede que no llegue nunca si el equipo no tienen conexión o no está encendido)

Para el código del ping "me basé" en uno que corría por internet (así me ahorraba picar todo el código para crear el paquete y eso) y chuta todo perfectamente excepto eso. Por si quereis echar un ojo al código:


public static int PingHost(string host)
{
//Declare the IPHostEntry
IPHostEntry serverHE, fromHE;
int nBytes = 0;
int dwStart = 0, dwStop = 0;
//Initilize a Socket of the Type ICMP
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);
socket.Blocking = false;

// Get the server endpoint
try
{
 serverHE = Dns.GetHostByName(host);
}
catch(Exception)
{
 // fail
 return -1;
}

// 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 = 8; //ICMP_ECHO
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 )
{
 // Error in Making Packet
 return -1;
}
       
// now get this critter into a UInt16 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 Uint16 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 )
{
 //.WriteLine("Error in Making Packet");
return -1;
}

dwStart = System.Environment.TickCount; // Start timing
//send the Pack over the socket
if ((nBytes = socket.SendTo(sendbuf, PacketSize, 0, epServer)) == -1) //SOCKET_ERROR
{  
 // Console.WriteLine("Socket Error cannot Send Packet");
}
// 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, SocketFlags.None, ref EndPointFrom);
 //nBytes = 1;
 if (nBytes == -1) //SOCKET_ERROR
 {
  dwStop = -1;
  recd=true;
  break;
 }
 else if(nBytes>0)
 {
  dwStop = System.Environment.TickCount - dwStart; // stop timing
  recd=true;
  break;
 }
 timeout=System.Environment.TickCount - dwStart;
 if(timeout>1000)
 {
  //Console.WriteLine("Time Out");
  dwStop = -1;
  recd=true;
 }
}
         
//close the socket
socket.Close();
               return dwStop;
}


El bucle en el que miro si vuelve el ping aun no está terminado porque como el problema lo tenía en la llamada al método ReceiveFrom() tampoco me he puesto (habría que cambiarlo porque el ReceiveFrom() se supone que tiene que devolver error inmediatamente mientras no haya datos en la cola de recepción si la llamada fuera verdaderamente no-bloqueante)

Pues nada, si a alguien se le ocurre algo que lo diga... (Dios seguro que se lo agradecerá con pocos hijos y muchos intentos (ole))

Yo de mientras voy a probar si el código original que encontré chuta bien solo o si también tiene ese problema :huh:

sync

synchrnzr

 Bueno, acabo de probar el código que encontré tal cual y tiene el mismo problema (si es que mira que llegar a ser chapucillas la gente)

Ya que estamos añadiré que, debugando se puede ver como la propiedad socket.Blocking es false (como tiene que ser para que no bloquee) hasta llegar al ReceiveFrom(). De hecho me podría haber ahorrado la línea en la que la pongo a false manualmente porque por defecto es false, pero al final uno no sabe ya qué hacer (nooo)

sync

gdl

 ¿Probaste a poner el Blocking=true? Por defecto los sockets suelen ser bloqueantes y si por defecto es false....

synchrnzr

 Si, lo he probado. Al socket le da igual si Blocking es true o false, siempre se comporta como blocking :P

sync

synchrnzr

 Bueno, compilando en modo Release he conseguido que en vez de colgarse suelte una excepción que puedo capturar, o sea que más o menos supongo que ya casi lo tengo arreglado. Lo malo es que me salta la excepción en casos en que el ping debería dar correcto. Bueno, ya terminaré de arreglarlo.

sync

PD: Ese pedazo de monólogo

synchrnzr

 Bueno, ya está el problema arreglado. El caso es que al ejecutar el programa desde el Visual Studio el thread se comportaba como bloqueante pero al ejecutar el .exe directamente (tanto la versión release como la debug) tampoco se comporta exactamente como dice la documentación pero almenos me deja capturar la excepción.

Ya colgaré el programilla en cuestión cuando lo acabe de pulir, por si a alguien le puede ser útil. El código paso, que está muy guarro y me da palo arreglarlo (tengo nombres de variables y funciones en catalán, castellano, inglés... y porque no sé más idiomas XD)

sync

zupervaca

 otra solucion es la clase casyncsocket aunque en c# no se si existe






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.