• Viernes 29 de Marzo de 2024, 06:46

Autor Tema:  Sockets  (Leído 1434 veces)

aTx

  • Nuevo Miembro
  • *
  • Mensajes: 8
    • Ver Perfil
Sockets
« en: Miércoles 25 de Febrero de 2009, 00:23 »
0
Hola a todos. He implementado una clase Socket que funciona mediante comandos numéricos y eventos, es decir, cada envío que se realiza se identifica mediante un comando numérico, que el receptor se encarga de recibir e invocar un evento indicando el número de comando y los datos que este lleva.

Por ahora es funcional, pero me gustaría contar con la revisión de alguien que tuviese cierta experiencia en Sockets de .Net y que me pueda aconsejar alguna mejora o cambio. Además, falla cuando los datos enviados son grandes (sobre los 100kbytes) y se envían otros datos a la vez, porque, según creo, mezcla el contenido de ambos paquetes y el resultado es erróneo (El fallo se suele producir en la línea 195, pues recibe un valor de TamañoSecuencia erróneo).

Aquí os dejo el código:

Código: C#
  1. using System;
  2. using System.IO;
  3. using System.Net.Sockets;
  4.  
  5. namespace Sockets
  6. {
  7.     /// <summary>
  8.     /// Delegado empleado para los eventos de recepción de comandos
  9.     /// </summary>
  10.     delegate void DelegadoComandoRecibido(CanalComunicacion canal, UInt16 comando, BinaryReader datos);
  11.  
  12.     /// <summary>
  13.     /// Administra una canal (Socket) de comunicación entre los dos extremos de la conexión
  14.     /// </summary>
  15.     class CanalComunicacion
  16.     {
  17.         /// <summary>
  18.         /// Constructor
  19.         /// </summary>
  20.         public CanalComunicacion(Socket socket)
  21.         {
  22.             Socket = socket;
  23.  
  24.             //Establecer opciones de socket
  25.             socket.LingerState = new LingerOption(true, 5);
  26.  
  27.             //Establecer recepción asíncrona
  28.             comenzarRecepcion();
  29.         }
  30.  
  31.         /// <summary>
  32.         /// Destructor
  33.         /// </summary>
  34.         ~CanalComunicacion()
  35.         {
  36.             Cerrar();
  37.         }
  38.  
  39.         #region Campos
  40.  
  41.         /// <summary>
  42.         /// Socket usado para el envío y recepción de datos
  43.         /// </summary>
  44.         public readonly Socket Socket;
  45.  
  46.         public bool Conectado
  47.         {
  48.             get
  49.             {
  50.                 return Socket.Connected;
  51.             }
  52.         }
  53.  
  54.         #endregion
  55.  
  56.         /// <summary>
  57.         /// Evento invocado cuando se recibe un comando por este canal
  58.         /// </summary>
  59.         public event DelegadoComandoRecibido ComandoRecibido;
  60.  
  61.         /// <summary>
  62.         /// Evento invocado cuando se cierra el canal o un error corta la comunicación
  63.         /// </summary>
  64.         public event EventHandler CanalCerrado;
  65.  
  66.         /// <summary>
  67.         /// Cierra la comunicación entre los dos extremos
  68.         /// </summary>
  69.         public void Cerrar()
  70.         {
  71.             if (Socket.Connected)
  72.             {
  73.                 Socket.Shutdown(SocketShutdown.Both);
  74.                 Socket.Close();
  75.             }
  76.  
  77.             if (CanalCerrado != null)
  78.                 CanalCerrado(this, EventArgs.Empty);
  79.         }
  80.  
  81.         /// <summary>
  82.         /// Envía un comando al otro extremo de la conexión por el canal especificado
  83.         /// </summary>
  84.         public void EnviarComando(UInt16 comando, params object[] datos)
  85.         {
  86.             MemoryStream buffer = new MemoryStream(2 + datos.Length*50);
  87.             BinaryWriter escritor = new BinaryWriter(buffer);
  88.             UInt32 tamañoSecuencia = 0;
  89.                 //Este valor es el primer elemento que se envía, pero se calcula al finalizar de generar el buffer
  90.  
  91.             escritor.Write(tamañoSecuencia);
  92.             escritor.Write(comando);
  93.  
  94.             foreach (object parametro in datos)
  95.             {
  96.                 if (parametro is string)
  97.                 {
  98.                     escritor.Write(parametro.ToString());
  99.                 }
  100.                 if (parametro is byte[])
  101.                 {
  102.                     byte[] bytes = (byte[]) parametro;
  103.                     escritor.Write((UInt32) bytes.Length);
  104.                     escritor.Write(bytes);
  105.                 }
  106.                 else if (parametro is UInt16)
  107.                 {
  108.                     escritor.Write((UInt16) parametro);
  109.                 }
  110.                 else if (parametro is UInt32)
  111.                 {
  112.                     escritor.Write((UInt32) parametro);
  113.                 }
  114.                 else if (parametro is UInt64)
  115.                 {
  116.                     escritor.Write((UInt64) parametro);
  117.                 }
  118.                 else if (parametro is int)
  119.                 {
  120.                     escritor.Write((int) parametro);
  121.                 }
  122.             }
  123.  
  124.             //Calcular el tamaño de la secuencia y escribirlo en el buffer
  125.             tamañoSecuencia = (UInt32) buffer.Length - 4; //No contar el tamaño propio del numero (4 bytes)
  126.             buffer.Position = 0;
  127.             escritor.Write(tamañoSecuencia);
  128.  
  129.             Socket.BeginSend(buffer.GetBuffer(), 0, (int) buffer.Length, 0, new AsyncCallback(finEnvio), buffer);
  130.         }
  131.  
  132.         /// <summary>
  133.         /// Finaliza un envío asíncrono y libera los recursos
  134.         /// </summary>
  135.         private void finEnvio(IAsyncResult ar)
  136.         {
  137.             if (Socket.Connected == false)
  138.             {
  139.                 Cerrar();
  140.             }
  141.             else
  142.             {
  143.                 Socket.EndSend(ar);
  144.  
  145.                 MemoryStream buffer = ar.AsyncState as MemoryStream;
  146.                 if (buffer != null)
  147.                     buffer.Close();
  148.             }
  149.         }
  150.  
  151.         /// <summary>
  152.         /// Comienza la recepción asíncrona de los datos enviados por el otro extremo
  153.         /// </summary>
  154.         private void comenzarRecepcion()
  155.         {
  156.             if (Socket.Connected == false)
  157.             {
  158.                 Cerrar();
  159.             }
  160.             else
  161.             {
  162.                 Buffer buffer = new Buffer { BytesBuffer = new byte[4], TamañoSecuencia = -1 };
  163.                 Socket.BeginReceive(buffer.BytesBuffer, 0, buffer.BytesBuffer.Length, 0, new AsyncCallback(finRecepcion),
  164.                                     buffer);
  165.             }
  166.         }
  167.  
  168.         class Buffer
  169.         {
  170.             public Int32 TamañoSecuencia;
  171.             public byte[] BytesBuffer;
  172.         }
  173.  
  174.         /// <summary>
  175.         /// Termina de recibir los datos enviados por el otro extremo de la conexión,
  176.         /// y los procesa
  177.         /// </summary>
  178.         private void finRecepcion(IAsyncResult ar)
  179.         {
  180.             if (Socket.Connected == false)
  181.             {
  182.                 Cerrar();
  183.                 return;
  184.             }
  185.             int recibidos = Socket.EndReceive(ar);
  186.  
  187.             if (recibidos > 0)
  188.             {
  189.                 Buffer buffer = (Buffer)ar.AsyncState;
  190.  
  191.                 if (buffer.TamañoSecuencia < 0)//Recibido tamaño de la próxima secuencia
  192.                 {
  193.                     buffer.TamañoSecuencia = BitConverter.ToInt32(buffer.BytesBuffer, 0);
  194.                     //Recibir el resto de la secuencia
  195.                     buffer.BytesBuffer = new byte[buffer.TamañoSecuencia];
  196.                     Socket.BeginReceive(buffer.BytesBuffer, 0, buffer.TamañoSecuencia, 0,
  197.                                         new AsyncCallback(finRecepcion), buffer);
  198.                 }
  199.                 else//Datos recibidos
  200.                 {
  201.                     //Comenzar a recibir siguiente comando
  202.                     comenzarRecepcion();
  203.  
  204.                     //Invocar eventos
  205.                     MemoryStream bufferStream = new MemoryStream(buffer.BytesBuffer);
  206.                     BinaryReader lector = new BinaryReader(bufferStream);
  207.  
  208.                     UInt16 comando = lector.ReadUInt16();
  209.                     if (ComandoRecibido != null)
  210.                         ComandoRecibido(this, comando, lector);
  211.  
  212.                     lector.Close();
  213.                 }
  214.             }
  215.             else
  216.             {
  217.                 Cerrar();
  218.             }
  219.         }
  220.     }
  221. }
  222.  

Un Saludo.