Foro de elhacker.net

Programación => .NET (C#, VB.NET, ASP) => Mensaje iniciado por: DeS_TRoZaDo en 9 Noviembre 2010, 21:26 pm



Título: Problema con Sockets C#
Publicado por: DeS_TRoZaDo en 9 Noviembre 2010, 21:26 pm
Buenas.

Tengo un servidor, que recibe conexiones de muchos clientes, lo hago usando las clases TcpListener para el servidor y TcpClient para los clientes con su respectivo NetworkStream para enviar y recibir datos.

Entonces, quiero que veais el codigo a ver si veis algo mal, por que si lo depuro, y voy linea por linea con el F11 dandole paso yo funciona perfecto, en el momento que lo dejo libre, falla, por lo cual no puedo saber donde es, un ejemplo, para enviar un string a la conexion hago esto en el que va a recibir:

Código
  1. public string recibirString()
  2.        {
  3.            if (stream == null)
  4.                stream = conexion.GetStream();
  5.            int longitud = recibirLongitud();
  6.            //stream = conexion.GetStream();
  7.            Byte[] bytes = new Byte[longitud];
  8.            Int32 i;
  9.            String datos = String.Empty;
  10.            if ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
  11.            {
  12.                datos = System.Text.Encoding.UTF8.GetString(bytes, 0, i);
  13.                return datos;
  14.            }
  15.            return datos;
  16.        }
  17.  

y recibirLongitud es:

Código
  1. private int recibirLongitud()
  2.        {
  3.            if (stream == null)
  4.                stream = conexion.GetStream();
  5.            Int32 longitud = 0;
  6.            Byte[] longitudByte = new Byte[4];
  7.            //stream = conexion.GetStream();
  8.            stream.Read(longitudByte, 0, longitudByte.Length);
  9.            longitud = BitConverter.ToInt32(longitudByte, 0);
  10.            return longitud;
  11.        }
  12.  

Eso el que lo recibe, y el que envia hace esto cuando ese esta esperando a recibir:

Código
  1. public bool enviarString(string mensaje)
  2.        {
  3.            if (stream == null)
  4.                stream = conexion.GetStream();
  5.            try
  6.            {
  7.                Byte[] paquete = System.Text.Encoding.UTF8.GetBytes(mensaje);
  8.                enviarLongitud(paquete);
  9.                stream.Write(paquete, 0, paquete.Length);
  10.                stream.Flush();
  11.                return true;
  12.            }
  13.            catch { return false; }
  14.        }
  15.  

donde enviarLongitud es:

Código
  1. private bool enviarLongitud(Byte[] paquete)
  2.        {
  3.            if (stream == null)
  4.                stream = conexion.GetStream();
  5.            try
  6.            {
  7.                int longitud = paquete.Length;
  8.                byte[] longitudBytes = BitConverter.GetBytes(longitud);
  9.                stream.Write(longitudBytes, 0, longitudBytes.Length);
  10.                stream.Flush();
  11.                return true;
  12.            }
  13.            catch { return false; }
  14.        }
  15.  

Graaaacias por leer.

Algun comentario?  :(

EDITO: stream en este caso seria el NetworkStream y conexion es el TcpClient.


Título: Re: Problema con Sockets C#
Publicado por: Lunfardo en 9 Noviembre 2010, 23:44 pm
la lectura la tenes que hacer con un while, hasta que hayas leido la misma longuitud de caracter que los esperados.


no basta con un simple "read" por que por el protocolo TCP los mensajes llegan cortados
Código
  1. while (BytesRecidos < BytesEsperados) {
  2. if ((B = ELStream.Read(byteBuffer, BytesRecibidos,
  3.       BytesRecibidos - BytesEsperados)) == 0) {
  4.       Console.WriteLine("fallo");
  5.        break;
  6.        }
  7.  
  8. BytesRecibidos += B;
  9. }
  10.  
  11.  


Espero que se entienda xD , si empieza a leer 0 bytes, es que algo funciona mal =)



Título: Re: Problema con Sockets C#
Publicado por: DeS_TRoZaDo en 10 Noviembre 2010, 00:01 am
Estas seguro de eso? yo esque internamente no se como funciona, pero recibir recibe bien, el problema es que despues de recibir, en algun momento, el stream o el tcpClient se peta y da un DisposedObject, pero recibir, cuando recibe, recibe bien.

EDIT: Lo que realmente me jode, es que si pongo un punto de interrupcion, y voy paso a paso, en el que envia los datos, con el F11, haciendolo, va todo perfecto, le mande lo que le mande y las veces que se lo mande, pero en el momento que quito el punto de interrupcion, se peta. :S:S me esta jodiendo mucho eso.


Título: Re: Problema con Sockets C#
Publicado por: Lunfardo en 10 Noviembre 2010, 00:11 am
seguro estoy,


proba cerrando los sockets una vez terminada la funcion.


stream.Close();


la longuitud la podes representar con un int de 4 bytes, por lo menos yo lo hacia asi para saber el peso de lo esperado sin complicaciones.


Título: Re: Problema con Sockets C#
Publicado por: DeS_TRoZaDo en 10 Noviembre 2010, 00:18 am
Ya he probado con eso, lo que pasa es que la conexion es continua, si hago el stream.Close() peta por todos lados, por que tanto cliente como servidor estan en continua comunicacion, creo que igual he encontrado el problema, por que he reducido el tamaño de los paquetes que envia y ya no peta, es decir, hay un maximo para enviar de 1 tirada? se puede aumentar si lo hay? solo estoy enviando puro string :S me extraña que sea algo de esto por que entonces ya si quisiera enviar una imagen me puede dar algo pero.... si reduciendo el tamaño a enviar ha funcionado.... :S


Título: Re: Problema con Sockets C#
Publicado por: Lunfardo en 10 Noviembre 2010, 00:22 am
hace lo del while que te puse al principio , ya que i y bytes.Lenght pueden no coincidir, te tenes que asegurar que lo haga antes de decifrarlo
Código
  1.  
  2.  if ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
  3.            {
  4.                datos = System.Text.Encoding.UTF8.GetString(bytes, 0, i);
  5.                return datos;
  6.            }
  7.  
  8.  
  9. fijate asi
  10.  
  11.  
  12. int recibidos=0;int Rcvd;
  13. while (recibidos < bytes.Lenght) {
  14.   if ((Rcvd = stream.Read(bytes, recibidos,
  15.   bytes.Length - recibidos)) == 0) {
  16.   Console.WriteLine("error");
  17.   break;
  18. }
  19.  
  20. datos = System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Lenght);
  21. return datos;
  22.  
  23.  



Título: Re: Problema con Sockets C#
Publicado por: DeS_TRoZaDo en 10 Noviembre 2010, 00:26 am
Voy a probarlo ahora mismo, otra duda, el stream = conexion.GetStream(); cuando hay que hacerlo? con 1 vez basta? o cada vez que vaya a enviar y recibir?


Título: Re: Problema con Sockets C#
Publicado por: Lunfardo en 10 Noviembre 2010, 00:33 am
con una vez basta, pero el servidor y el cliente tiene que estar sintonizados para cuando el cliente termine de recibir lo que el servidor tenga para enviar ambos cierren los sockets, sino el servidor no podria recibir otra solicitud.

ademas una vez que se termine el proceso, el servidor deberia quedar parado en un punto de espera para responde a una nueva solicitud.

te aconsejo que leas tcp/ip sockets in c # si te quedan muchas dudas


Título: Re: Problema con Sockets C#
Publicado por: DeS_TRoZaDo en 10 Noviembre 2010, 00:39 am
la lectura la tenes que hacer con un while, hasta que hayas leido la misma longuitud de caracter que los esperados.


no basta con un simple "read" por que por el protocolo TCP los mensajes llegan cortados
Código
  1. while (BytesRecidos < BytesEsperados) {
  2. if ((B = ELStream.Read(byteBuffer, BytesRecibidos,
  3.       BytesRecibidos - BytesEsperados)) == 0) {
  4.       Console.WriteLine("fallo");
  5.        break;
  6.        }
  7.  
  8. BytesRecibidos += B;
  9. }
  10.  
  11.  


Espero que se entienda xD , si empieza a leer 0 bytes, es que algo funciona mal =)



En el if, el bytesRecibidos - bytesEsperado mmmm no va bien bien, bytesRecibidos la primera vez es 0 por que hemos recibido 0, y los esperados son 1000 alomejor, 0 - 1000 peta por argumentException que querias poner exactamente? Se ha quedado asi:

Código
  1. public string recibirString()
  2.        {
  3.            if (stream == null)
  4.                stream = conexion.GetStream();
  5.            int longitud = recibirLongitud();
  6.            Byte[] bytes = new Byte[longitud];
  7.            Int32 i;
  8.            String datos = String.Empty;
  9.            int bytesRecibidos = 0;
  10.            while (bytesRecibidos < longitud)
  11.            {
  12.                if ((i = stream.Read(bytes, bytesRecibidos, bytesRecibidos - longitud)) == 0)
  13.                {
  14.                    break;
  15.                }
  16.                bytesRecibidos += i;
  17.            }
  18.            return datos;
  19.        }
  20.  

Si, esta bastante controlado el tema de los sockets, ya te digo que el programa funciona, si el paquete no es grande, y aun siendo grande, si lo hago linea a linea, tambien va.


Título: Re: Problema con Sockets C#
Publicado por: Lunfardo en 10 Noviembre 2010, 00:44 am
tenes razon , es BytesEsperado-BytesRecibidos lo bytes que tiene que tratar de leer


Título: Re: Problema con Sockets C#
Publicado por: DeS_TRoZaDo en 10 Noviembre 2010, 01:01 am
Asi funciona:

Código
  1. while (bytesRecibidos < longitud)
  2.            {
  3.                i = stream.Read(bytes, bytesRecibidos, 1);
  4.                bytesRecibidos += i;
  5.            }
  6.            datos = System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length);
  7.            return datos;
  8.  

el stream.Read devuelve 1 o 0? o que valores devuelve? por que funciona igual con un 1 como ultimo parametro y con BytesEsperado-BytesRecibidos??


Título: Re: Problema con Sockets C#
Publicado por: Lunfardo en 10 Noviembre 2010, 01:04 am
stream.Read devuelve la cantidad de Bytes que pudo leer,

si pones 1 en vez de BytesEsperados-BytesRecibidos vas a estar leyendo de a un byte.


ya funciona todo bien ?


Título: Re: Problema con Sockets C#
Publicado por: DeS_TRoZaDo en 10 Noviembre 2010, 01:05 am
Si, muchas gracias, ademas voy a dejar lo de bytesEsperados - BytesRecibidos, pero no entiendo muy bien por que asi va y como lo tenia yo no pero bueno :S lo estudiare mejor mañana que tengo que madrugar xD

AAAAAhhh vale vale, es por si de una tacada, no puede leer entero el paquete, vuelve a leer lo que le falta, por eso le sumas la "i" que es lo que ha podido leer, vaaale vale, muchas gracias :)


Título: Re: Problema con Sockets C#
Publicado por: [D4N93R] en 10 Noviembre 2010, 01:22 am
Acá en este subforo hay dos guías buenas de Sockets y TcpListener/Client , están en el recopilatorio, solo en caso de que no las hayan leído! :)


Título: Re: Problema con Sockets C#
Publicado por: DeS_TRoZaDo en 10 Noviembre 2010, 09:54 am
Si, me los he leido, pero son algo basicos para este caso en concreto, que ya estaba todo eso hecho y que fallaba cuando el paquete era demasiado grande y se partia en 2 y yo solo leia el primer trozo que llegaba, por otro lado aprovecho para preguntar una duda, con un TcpListener por 1 puerto, y 1 solo TcpClient a ese puerto, no puedo tener 2 threads mandando datos es decir, por ejemplo, si quisiera estar enviando por un lado informacion de posibles errores cuando salte, y por otro lado estar contestando las peticiones del servidor? :S No se si me explico, creo que me toca abrir 2 puertos, pero no quiero hacer eso jeje entonces quizas haya alguna manera de que envie uno un poco, el otro otro poco, y asi parezca que lo hacen los dos a al vez y en realidad lo hacen de 1 en 1? Se me entiende? xD


Título: Re: Problema con Sockets C#
Publicado por: Choclito en 11 Noviembre 2010, 18:10 pm
ola bueno ahi dejo mi granito de arena si ayuda en algo chevre

ServidorPaquete

Código
  1. private UdpClient cliente;      
  2.   private IPEndPoint puntoRecepcion;
  3.  
  4.   // inicializa las variables y el subproceso para recibir paquetes
  5.   private void ServidorPaquetesForm_Load( object sender, EventArgs e )
  6.   {
  7.      cliente = new UdpClient(50000);
  8.      puntoRecepcion = new IPEndPoint(new IPAddress(0), 0);
  9.      Thread lecturaThread = new Thread(new ThreadStart(EsperarPaquetes));
  10.      lecturaThread.Start();                                    
  11.   }
  12.  
  13.   // cierra el servidor
  14.   private void ServidorPaquetesForm_FormClosing( object sender,
  15.      FormClosingEventArgs e )
  16.   {        
  17.      System.Environment.Exit( System.Environment.ExitCode );
  18.   } // fin del método ServidorPaquetesForm_FormClosing
  19.  
  20.   // delegado que permite llamar al método MostrarMensaje
  21.   // en el subproceso que crea y mantiene la GUI
  22.   private delegate void DisplayDelegate( string message );  
  23.  
  24.   // el método MostrarMensaje establece la propiedad Text de mostrarTextBox
  25.   // de una manera segura para el proceso
  26.   private void MostrarMensaje( string mensaje )
  27.   {
  28.      // si la modificación de mostrarTextBox no es segura para el subproceso
  29.      if ( mostrarTextBox.InvokeRequired )
  30.      {
  31.         // usa el método heredado Invoke para ejecutar MostrarMensaje
  32.         // a través de un delegado
  33.         Invoke( new DisplayDelegate( MostrarMensaje ),          
  34.            new object[] { mensaje } );                          
  35.      } // fin de if
  36.      else // sí se puede modificar mostrarTextBox en el subproceso actual
  37.         mostrarTextBox.Text += mensaje;
  38.   }
  39.  
  40.   // espera a que llegue un paquete
  41.   public void EsperarPaquetes()
  42.   {
  43.      while ( true )
  44.      {
  45.         // prepara el paquete
  46.         byte[] datos = cliente.Receive( ref puntoRecepcion );
  47.         MostrarMensaje( "\r\nSe recibió paquete:" +
  48.            "\r\nLongitud: " + datos.Length +
  49.            "\r\nContenido: " +
  50.            System.Text.Encoding.ASCII.GetString( datos ) );          
  51.  
  52.         // devuelve (eco) la información del paquete de vuelta al cliente
  53.         MostrarMensaje( "\r\n\r\nEnviando de vuelta datos al cliente..." );
  54.         cliente.Send( datos, datos.Length, puntoRecepcion );
  55.         MostrarMensaje( "\r\nPaquete enviado\r\n" );
  56.      } // fin de while
  57.   }  
  58.  
ClientePaquete

Código
  1. private UdpClient cliente;      
  2.   private IPEndPoint puntoRecepcion;
  3.  
  4.   // inicializa las variables y el subproceso para recibir paquetes
  5.   private void ClientePaquetesForm_Load( object sender, EventArgs e )
  6.   {
  7.      puntoRecepcion = new IPEndPoint( new IPAddress( 0 ), 0 );
  8.      cliente = new UdpClient( 50001 );                        
  9.      Thread subproceso =                                        
  10.         new Thread( new ThreadStart( EsperarPaquetes ) );    
  11.      subproceso.Start();                                        
  12.   } // fin del método ClientePaquetesForm_Load
  13.  
  14.   // cierra el cliente
  15.   private void ClientePaquetesForm_FormClosing( object sender,
  16.      FormClosingEventArgs e )
  17.   {
  18.      System.Environment.Exit( System.Environment.ExitCode );
  19.   } // fin del método ClientePaquetesForm_FormClosing
  20.  
  21.   // delegado que permite llamar al método MostrarMensaje
  22.   // en el subproceso que crea y mantiene la GUI
  23.   private delegate void DisplayDelegate( string message );  
  24.  
  25.   // el método MostrarMensaje establece la propiedad Text de mostrarTextBox
  26.   // de una manera segura para el subproceso
  27.   private void MostrarMensaje( string mensaje )
  28.   {
  29.      // si la modificación de mostrarTextBox no es segura para el subproceso
  30.      if ( mostrarTextBox.InvokeRequired )
  31.      {
  32.         // usa el método heredado Invoke para ejecutar MostrarMensaje
  33.         // a través de un delegado
  34.         Invoke( new DisplayDelegate( MostrarMensaje ),          
  35.            new object[] { mensaje } );                          
  36.      } // fin de if
  37.      else // sí se puede modificar mostrarTextBox en el subproceso actual
  38.         mostrarTextBox.Text += mensaje;
  39.   } // fin del método MostrarMensaje
  40.  
  41.   // envía un paquete
  42.   private void entradaTextBox_KeyDown( object sender, KeyEventArgs e )
  43.   {
  44.      if ( e.KeyCode == Keys.Enter )
  45.      {
  46.         // crea un paquete (datagrama) como objeto string
  47.         string paquete = entradaTextBox.Text;  
  48.         mostrarTextBox.Text +=
  49.            "\r\nEnviando paquete que contiene: " + paquete;
  50.  
  51.         // convierte el paquete en arreglo de bytes
  52.         byte[] datos = System.Text.Encoding.ASCII.GetBytes( paquete );
  53.  
  54.         // envía el paquete al servidor en el puerto 50000              
  55.         cliente.Send( datos, datos.Length, "127.0.0.1", 50000 );
  56.         mostrarTextBox.Text += "\r\nPaquete enviado\r\n";
  57.         entradaTextBox.Clear();
  58.      } // fin de if
  59.   } // fin del método entradaTextBox_KeyDown
  60.  
  61.   // espera a que lleguen los paquetes
  62.   public void EsperarPaquetes()
  63.   {
  64.      while ( true )
  65.      {
  66.         // recibe arreglo de bytes del servidor
  67.         byte[] datos = cliente.Receive( ref puntoRecepcion );
  68.  
  69.         // envía el paquete de datos al control TextBox
  70.         MostrarMensaje( "\r\nPaquete recibido:" +
  71.            "\r\nLongitud: " + datos.Length + "\r\nContenido: " +
  72.            System.Text.Encoding.ASCII.GetString( datos ) + "\r\n" );
  73.      } // fin de while
  74.   } // fin del método EsperarPaquetes