Está en la página 1de 37

Apuntes de Computación en la Red. Prácticas demostrativas de .

NET 

Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces, 
paquetes y código intermedio. 
 

El  objetivo  de  esta  práctica  es  programar  una  aplicación  sencilla  para  familiarizarnos  con  el 
entorno  de  programación  de  .NET.    Durante  el  desarrollo  de  las  prácticas  se  van  realizar 
prácticas para dispositivos limitados (PDA). 

Conociendo el Entorno de Desarrollo 
Comenzamos por crear un nuevo proyecto con Visual Studio 2005 o 2008: 

Una  vez  pulsemos,  aparecerá 


en  la  pantalla  los  posibles 
proyectos.  El  número  y  tipo  de 
proyectos  dependerá  de  los 
SDKs instalados en el sistema: 

Vamos  a  crear  un  proyecto 


Visual  C#,  para  dispositivo 
limitado (Smart Device), usando 
el  SDK  de  Windows  Mobile  5.0 
o  6.0  dependiendo  del  que 
tengamos instalado.  
 
 
 
 
 
La plantilla del proyecto es Empty Project. Le damos un nombre, por ejemplo MiAplicacion o 
como uno desee. Seleccionamos la ubicación que más nos convenga. 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

 Todos  los  proyectos  que  hagamos,  se  incorporan  a  una  solución,  daremos  el  nombre 
MiSolución o el que nos apetezca a la solución. Ten en cuenta que la solución es un conjunto 

de proyectos y el nombre debería representar algo común a todos los proyectos incluidos en 
él. 
Al  crear  el  proyecto,  podemos  ver  en  el  explorador  de  soluciones  (Si  no  aparece,  menú 
View[Ver]>Explorador de soluciones) que el proyecto está vacío completamente. 
 
Como  podemos  ver,  la  solución  no  contiene  ningún  fichero  de 
código.  Para  introducir  un  nuevo  fichero  de  código,  que  será  el 
programa  principal,  sobre  el 
proyecto  MiAplicación, 
haremos  click  con  el  botón 
derecho  y  pulsaremos  sobre 
añadir‐añadir elemento nuevo. 
 
Al  hacer  esto,  aparecen  varias 
posibilidades,  entre  las  que  se 
encuentra  Archivo  de  código. 
Hay  otras  plantillas,  como  la 
de  clase  o  interfaz,  que 
generan  parte  del  código,  la 
estructura etc… 
 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Llamaremos  a  este 
fichero  programa.cs.  En 
él  vamos  a  escribir  el 
código  de  la  primera 
aplicación  para  Windows 
Mobile. 
 
El  fichero  está  vacío, 
dado  que  no  se  ha 
utilizado  ninguna 
plantilla  de  clase  o  de 
interfaz. 
 
 
 

El programa principal 
Vamos a escribir el programa principal. Para ello se pueden utilizar las siguientes clausulas: 

 
public static int Main(),
 
public static void Main(),
 
public static void Main(string[] args)

public static int Main(string[] args)   

Vamos a probar el siguiente código, que calcula el factorial de un número entero de 64 bits. 

public class MiAplicacion


{
public static Int64 factorial(Int64 num)
{
if ((num == 1) || (num == 0))
return 1;
return num * factorial(num - 1);
}
public static void Main(string[] args)
{
MiAplicacion.factorial(2);
factorial(6);
}

Copiad  este  código  en  el  fichero  programa.cs.  Para  compilar, 


podeis hacer click con el botón derecho en el proyecto y pulsar en 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

generar  o  build.  Si  hacéis  esto  mismo  con  la  solución,  compilará  todos  los  proyectos 
contenidos en la solución. 

En la ventana de resultados (si no se ve la pestaña, pulsad en el menú Ver‐Resultados) podréis 
ver si la compilación ha sido correcta o no.  

Si  vamos  a  la  carpeta  donde  hemos  guardado  el  proyecto,  en  la  ruta 
MiSolucion\MiAplicacion\Bin\Debug  podemos  ver  dos  ficheros,  MiAplicación.exe  y 
MiAplicación.pdb. Estos ficheros tienen información de depuración, pueden ser un poco más 
lentos que los programas sin información de depuración. 

Si cambiáramos la configuración a Release (sin debug) crearía  un fichero más eficiente, pero 
en el caso que nos ocupa, vamos a aprender, así que dejamos el sistema en modo debug. 

Depurar el programa 
A  continuación  veremos  cómo  se  depura  un  programa  con  Visual  Studio.  Para  depurar, 
podemos poner puntos de interrupción pulsando en la parte gris del editor de texto, justo en 
la línea en la que queremos insertar el 
breakpoint  o  bien  mediante  el  menú 
debug. Si lo que queremos es ejecutar 
paso  a  paso  pulsamos  F10  o  para 
meternos dentro de las funciones F11 (menú debug StepOver, StepInto). 

Para probarlo usaremos un emulador.  En Visual Studio hay un desplegable que permite ver los 
emuladores instalados. 

En ese menú desplegable seleccionaremos el emulador que queramos ejecutar (es posible que 
al depurar nos pregunte de nuevo por el emulador a utilizar).  

Pulsaremos  ahora  F10  y  comenzará  la  ejecución.  Al  comenzar  la  depuración  el  entorno  de 
desarrollo cambia y nos muestra nuevas ventanas: 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Línea  donde  se 


encuentra  la 
ejecución 

 
Pila de llamadas Ventana  de 
 
Automático:  Variables    comandos… 
Variables  en  locales: 
uso  en  cada  Variables  en 
momento  el método 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Si pulsamos F10, ejecutará la primera instrucción MiAplicacion.factorial(2); y 
continuará por la siguiente.  Si en la siguiente   en lugar de pulsar F10, pulsamos F11, se 
introducirá en el método factorial, si posteriormente, en el método factorial volvéis a pulsar 
F11 en la llamada recursiva, volverá a llevaros a factorial.  

Comprobadlo, echadle un vistazo a la pila de llamadas y podréis ver el efecto de la 
recursividad en la pila de llamadas: 

Observad también como varía en valor de las variables mediante las ventanas de 
Automático y Variables Locales. Estas ventanas permiten cambiar el valor de las 
variables que se están utilizando. 

Las tripas del programa, MSIL (MS Intermediate Language) 
Para  ver  el  código  intermedio,  generado  por  el  compilador  de  C#,  tendremos  que  usar  una 
herramienta llamada ildasm.exe que es un desensamblador de MSIL. Como es posible que sea 
difícil de localizar dentro de la maraña de directorios de Windows y como probablemente no 
esté en el PATH, una buena forma de usar las utilizades asociadas a Visual Studio es mediante 
la consola Visual Studio Command Prompt. Cuando aparezca esta consola, ejecuta ildasm.exe 
y aparecerá una utilidad gráfica. 

Buscamos  el  fichero  binario  MiAplicación.exe  y  lo  analizamos  con  el  desensamblador  de 
lenguaje intermedio. Como se pude ver, no existe el método factorial, pero si nos fijamos en el 
main, podremos comprobar que, como medida de eficiencia, el compilador lo ha incluido en el 
interior de main. 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Más adelante veremos cómo varía el código intermedio con programas más complejos. 

Acceso a ficheros para depurar 
Ahora que sabemos cómo depurar un programa, ver el contenido del código intermedio etc, 
vamos  a  continuar.    Las  plataformas  Windows  Mobile  no  disponen  de  consola  (se  puede 
instalar  usando  algunas  utilidades  GNU)  por  lo  que  no  es  posible  hacer  depuración  sobre 
consola, pero si en fichero de texto, que además es muy útil. 

Para hacer esto vamos a crear un ensamblado o librería de log. En primer lugar vamos a dar un 
espacio  de  nombres  a  nuestra  aplicación.  Hasta  el  momento,  no  hemos  necesitado  que 
nuestra  aplicación  tuviera  un  nombre  único,  que  la  diferenciara  de  las  demás  a  efectos  de 
reutilizar  código,  pero  ahora  va  a  ser  necesario;  por  esta  razón,  cambiamos  el  código  de  la 
práctica por el siguiente: 

using System;

namespace ComputacionRed.MiAplicacion
{

public class MiAplicacion


{
public static void Main(string[] args)
{
MiAplicacion ma = new MiAplicacion();
/* de momento no hace nada */
}
}

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Acto  seguido  miramos  las  propiedades  de  la  aplicación  y  cambiamos  el  nombre  del 
ensamblado en la configuración: 

Una  vez  hecho  esto  vamos  a  crear  un  nuevo  proyecto.  Sobre  MiSolución,  botón  derecho 
Añadir  nuevo  proyecto.  Tipo  Class  Library.  El  nombre  que  le  daremos  será  UtilidadLog. 
Cambiamos el namespace de la aplicación tal y como aparece bajo estas líneas.  

using System;
using System.Collections.Generic;
using System.Text;

namespace Utilidades.UtilidadLog
{
public class Log
{
}
}
 

Actualice  la  información  en  las  propiedades,  de  forma  que  el  nombre  del  ensamblado  y  el 
espacio de nombres predeterminado sean Utilidades.UtilidadLog

Observa que el nombre de la clase es independiente del nombre del fichero, no ocurre 
igual en java. 

A continuación daremos funcionalidad a la clase de Log, de forma que podamos escribir 
información a un fichero que permita depurar el programa. Para ello, es necesario declarar en 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

el código mediante using qué parte de la Base Class Library se utilizará. En concreto usaremos 
System.IO.  

Para escribir en un fichero usaremos la clase TextWriter, cuya documentación puede 
encontrarse en http://msdn.microsoft.com/es‐es/library/system.io.textwriter(VS.80).aspx. La 
función de log se utilizará en adelante para probar el correcto funcionamiento del programa y 
debido a que las aplicaciones gráficas que veremos más adelante son multihilo (si pulsas un 
botón y la ejecución tarda, puede que al pulsar otro botón se genere otro hilo de ejecución) y a 
que el fichero sobre el que vamos a escribir es un recurso compartido: hay que usar un Mutex. 

El  paquete  que  tiene  la  implementación  de  TextWriter  es  System.IO  y  el  que  contiene  la 
implementación  de  Mutex  es  System.Threading.  A  continuación  se  muestra  como  utilizar 
ambos en el programa de la clase Log. Esta clase muestra cómo usar un mutex y como escribir 
en un fichero de texto. 

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Utilidades.UtilidadLog
{
public class Log
{
/* TextWriter */

TextWriter tw = null;
Mutex fileMutex;
int indent = 0;

public Log(string fileName)


{
tw = new StreamWriter(fileName,true);
fileMutex = new Mutex();
}
~Log()
{
tw.Flush();
tw.Close();
}
public void Trace(String msg)
{
fileMutex.WaitOne();
for (int i = 0; i < indent; i++) tw.Write("\t");
tw.Write(msg);
tw.Flush();
fileMutex.ReleaseMutex();
}

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

public void BeginTrace(String fname)


{
indent++;
Trace(DateTime.Now.Hour +":"+ DateTime.Now.Minute +
":: Entrando en " + fname + "\n");
}
public void EndTrace(String fname)
{
indent--;
Trace(DateTime.Now.Hour + ":" + DateTime.Now.Minute
+ ":: Entrando en " + fname + "\n");
}
public void Trace(String fname, String msg)
{
Trace(DateTime.Now.Hour + ":" + DateTime.Now.Minute
+ "::" + fname + "::" + msg + "\n");
}

}
}
}
 

Los atributos de la clase Log son una referencia a la clase Textwriter, que permite 
escribir al fichero; un semáforo Mutex, que controlará el acceso al recurso compartido 
(fichero) ; y una variable de tipo entero que almacena la indentación a añadir a cada 
línea.  
El constructor de la clase crea una instancia de la clase Textwriter proporcionándole el 
nombre del fichero a utilizar. Si compruebas la documentación del constructor de 
StreamWriter podrás ver qué implica el segundo parámetro (true). 
A continuación podemos ver una función cuanto menos extraña para aquellos sin 
experiencia en C++. Es la función ~Log() que se conoce como destructor. En C++ esa 
función se utiliza para liberar memoria una vez concluye la ejecución de la clase y el 
objeto se destruye. E n los lenguajes como Java o cualquiera de los presentes en .NET, 
no es necesario liberar memoria, eso lo hace el recolector de basura; en cambio, se 
permite el uso de esta función para realizar una serie de tareas antes de destruir el 
objeto (como en este caso, hacer flush y cerrar el fichero). Aunque no es necesario, en 
ocasiones es útil. 
El siguiente método, es Trace. Este método escribe una traza de log en el fichero. 
Primero comprueba el semáforo y si es necesario espera un tiempo dado hasta que 
deje de ser usado. En ese momento  tabula el texto, escribe el mensaje, hace flush y 
por último libera el semáforo para que otros métodos puedan usar el fichero. 
El resto de los métodos no requieren explicación. 

 
Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Utilizando la clase Log desde otro programa 
Para poder utilizar la clase Log desde MiAplicación, hacemos click con el botón derecho sobre 
la carpeta References contenida en el proyecto aplicación y luego sobre Add Reference. 
Vamos a la pestaña Proyectos y ahí encontraremos UtildadLog. La seleccionamos y pulsamos 
aceptar. 

A partir de ese momento podremos utilizar la 
clase  Log,  contenida  en  el  espacio  de 
nombres Utilidades.UtilidadLog. 

A continuación probaremos la clase Log, pero 
antes vamos a facilitar la tarea modificando 
las propiedades del emulador. Para ello, en el 
menú File del  emulador,  seleccionamos 
configure… cuando aparece el cuadro de 
diálogo en la caja de texto Shared Folder 
navegamos hasta la ruta donde se encuentre 
la aplicación compilada, es decir, carpetaDelProyecto\bin\debug. 

A partir de ese momento si abrimos el explorador de ficheros en la PDA emulada y navegamos, 
veremos que existe un directorio llamado Storage Card que simula una tarjeta SD introducida 
en el slot. Si consultamos los ficheros contenidos en ella, veremos cómo aparecen los 
contenidos en el directorio seleccionado. 

Ahora vamos a modificar el programa para  probar la clase de Log. Utilice el siguiente código: 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

using System;
using Utilidades.UtilidadLog;

namespace ComputacionRed.MiAplicacion
{

public class MiAplicacion


{
Log log;
public MiAplicacion()
{
log = new Log("\\Storage Card\\milog.txt");
}

public void mifuncion2()


{
log.BeginTrace("mifuncion2");
log.Trace("mifuncion2", "Un mensaje de
mifuncion2");
log.EndTrace("mifuncion2");
}
public void mifuncion()
{
log.BeginTrace("mifuncion");
log.Trace("mifuncion2", "Un mensaje de
mifuncion1");
mifuncion2();
log.EndTrace("mifuncion");
}
public static void Main(string[] args)
{
MiAplicacion ma = new MiAplicacion();
ma.mifuncion();
}
}

Como se puede apreciar, el fichero seleccionado para guardar los resultados del log se 
encuentra en la carpeta de la aplicación dentro del PC (no de la PDA). 

Lo siguiente que haremos, será probar la aplicación. Para ver el fichero con comodidad (puede 
verse directamente en la PDA emulada, pero debido a que el tamaño de la pantalla no es muy 
grande, es preferible hacerlo en el PC) lo abrimos con visual studio.  A partir de este momento 
no hace falta cerrarlo y volverlo a abrir para ver los cambios, si el fichero cambia, Visual Studio 
lo notificará. 

El resultado de la ejecución debe ser algo similar a esto: 
Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

2:34:: Entrando en mifuncion


2:36:: Entrando en mifuncion
2:36::mifuncion2::Un mensaje de mifuncion1
2:36:: Entrando en mifuncion2
2:36::mifuncion2::Un mensaje de mifuncion2
2:36:: Entrando en mifuncion2
2:36:: Entrando en mifuncion
 

Observe que una llamada a una función dentro de otra función aumenta la 
indentación. 

Práctica 2. Introducción a .NET, programación gráfica. 
 

El  objetivo  de  esta  práctica  es  programar  una  aplicación  sencilla  para  familiarizarnos  con  el 
entorno visual de programación de .NET con Formularios de Windows. 

Conociendo el Entorno de Desarrollo 
Comenzamos por crear un nuevo proyecto con Visual Studio 2005 o 2008: 

Una  vez  pulsemos,  aparecerá 


en  la  pantalla  los  posibles 
proyectos.  El  número  y  tipo  de 
proyectos  dependerá  de  los 
SDKs instalados en el sistema: 

Vamos  a  crear  un  proyecto 


Visual  C#,  para  dispositivo 
limitado (Smart Device), usando 
el  SDK  de  Windows  Mobile  5.0 
o  6.0  dependiendo  del  que 
tengamos instalado.  
 
La  plantilla  del  proyecto  es  Device  Application.  Le  damos  un  nombre,  por  ejemplo  miApp. 
Seleccionamos  la 
ubicación  que  más 
nos convenga. 
 
Todos  los  proyectos 
que  hagamos,  se 
incorporan  a  una 
solución, 
utilizaremos  la 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

solución que ya teníamos creada. 

Una vez creado, aparecerá el interfaz de usuario. En el que podemos ver una imagen de lo que 
será  el  programa.    Además  existen  menús  útiles  para  el  desarrollo  como  son  (Están 
identificados en la imagen): 

 El explorador de soluciones 
 Vista de clases 
 Propiedades 
 Toolbox 
 Resultados 
 Lista de errores 

Si  no  ves  alguno  de  las  pestañas  marcadas  con  círculos  sobre  las  imágenes,  puedes  usar  el 
menú View (ver) y pulsar sobre cada una de las que necesitas. Luego puedes arrastrarlas por la 
pantalla para colocarlas donde te resulten más cómodas de usar. 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Aplicación Hello world 
Se trata de la aplicación que todo el mundo ha hecho alguna vez para comenzar a aprender un 
lenguaje. La aplicación tiene el efecto positivo de mostrar al usuario que algo funciona, a partir 
de ahí… lo que imagines  

Un vistazo al código 
Antes de comenzar con la aplicación vamos a echar un vistazo al código generado por Visual 
Studio y que nos permitirá programar la aplicación. 

Vamos a ver el programa principal, la clase que permite la ejecución del formulario o ventana 
sobre la que  colocaremos  controles como botones  o cajas de  texto. Para ver el  código pulse 
sobre program.cs como indica la figura: 

Al  hacer  esto,  pulsar  sobre  Ver  Código  o  hacer  doble  click  sobre 
Program.cs, aparece el código en la pantalla principal. 

El código que se verá será este (o muy parecido): 

 
using System;
  using System.Collections.Generic;
using System.Windows.Forms;
 
namespace miApp
  {
static class Program
{
  /// <summary>
/// The main entry point for the
  application.
/// </summary>
  [MTAThread]
static void Main()
  {
Application.Run(new Form1());
}
  }

 

Este código es un programa principal como el que hemos visto en la anterior práctica, la única 
diferencia es que ahora existe un atributo llamado  MTAThread que se usa en las aplicaciones 
de Formularios para conocer el lugar en el que comienza el programa. 

Consulta el código de la clase Form1.cs, comprobarás que es una clase que hereda de 
Form (la que gestiona los formularios en Windows).  

A continuación vamos a añadir funcionalidad a la aplicación. Para comenzar, debes poder usar 
el ToolBox o caja de herramientas. En ella encontrarás componentes gráficos para añadir a tu 
aplicación. 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Para añadir nuevos controles gráficos, simplemente arrástralos desde el toolbox directamente 
a la pantalla. 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Añade varios elementos: 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

 Un textbox 
 Un botón con el nombre hola 
 Otro con el nombre mundo 

Cada uno de los controles que se colocan en la pantalla tiene una serie de propiedades. Una es 
el nombre dentro del programa Name otra es la información que aparece en pantalla Caption. 
Al  hacer  dobre  click  sobre  un  botón,  Visual  Studio  creará  un  método.  Este  método  puede 
usarse para cambiar las propiedades de los controles. 

Añada también unas etiquetas Label de modo que el interfaz de usuario quede de la siguiente 
manera: 

Tu turno: 
Da un nombre adecuado al nameSpace 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Coloca entradas de Log para ver qué ocurre con la aplicación. Pon una al comienzo de 
cada clase y método, de forma que veas el flujo de la ejecución. 
 Para ello, tendrás que importar la clase de Log (añadir referencia…) 
 Tendrás que pasar la instancia de Log de una clase a otra para que todos 
escriban sobre el mismo fichero. Para ello, añade un atributo Log a la clase 
Form1. 

public partial class Form1 : Form


{
Log log;
public Form1()
{
InitializeComponent();
log = new Log("\\Storage Card\\fichero.txt");
}
}

Añade funcionalidad a los métodos de los botones Hola y Mundo de forma que al 
pulsar el primero aparezca la palabra Hola en el cuadro de texto. Para modificar el 
texto utiliza la propiedad Text de del cuadro de texto. 

 
   

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Práctica 3. Introducción a sockets en .NET 
 

Ahora  que  conoces  el  API  de  sockets  de  otros  sistemas  operativos  y  lenguajes  como  Java, 
vamos a aprender cómo usar sockets desde .NET con el lenguaje C#. 

En  esta  práctica,  usaremos  el  Framework  de  .NET  en  lugar  del  Compact  Framework,  en 
cualquier caso, el contenido de estas prácticas es trasladable a pocket pc directamente. 

Estructura de clases 
 

Para  utilizar  sockets  es  necesario  importar  las  librerías  de  la  class  library  System.Net y
System.Net.Sockets. Para ello, creamos un proyecto de tipo aplicación visual
con el SDK correspondiente y le damos el nombre de VistaCliente.cs al fichero
de código con el formulario. El otro fichero será program.cs. Introducimos el
siguiente código en los ficheros:

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

  /* Programa.cs */
using System;
using System.Text;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;

namespace ComputacionRed.Sockets.Cliente
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[MTAThread]
static void Main()
{

}
}

/* VistaCliente.cs [Formulario-Ver código]*/


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace ComputacionRed.Sockets.Cliente
{
public partial class VistaCliente : Form
{
public VistaCliente()
{
InitializeComponent();
}
}

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

La clase VistaCliente, es una clase que hereda de Form, por tanto se utiliza para proporcionar 
una  GUI  al  usuario.  Por  otro  lado,  tendremos  una  clase  controlador  ClienteConnection  que 
crearemos dentro del fichero programa.cs: 

  /* Programa.cs */
using System;
using System.Text;
  using System.Collections.Generic;
using System.Windows.Forms;
  using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
 
namespace ComputacionRed.Sockets.Cliente
  {
static class Program
{
  /// <summary>
 
/// The main entry point for the application.
/// </summary>
[MTAThread]
static void Main()
{

}
}

public class ClienteConnection


{
IPAddress dirServidor;
Int32 serverPort = 0;
IPEndPoint endPointServidor;

Socket socket;

Form vv = null;
writeLog log = null;
public ClienteConnection(Form vv)
{
this.vv = vv;
}
/* destructor */
~ClienteConnection()
{
try
{
if (socket != null)
if (socket.Connected)
socket.Disconnect(false);
}
catch (Exception ex)
{
/* lo hemos intentado ... */
}
}

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

En la clase ClienteConnection tendremos los siguientes atributos: 

 IPAddress dirServidor : Estructura de dirección IP  para conectar con el servidor 
o http://msdn.microsoft.com/en‐us/library/system.net.ipaddress.aspx 
 IPEndPoint endPointServidor: Contiene  tanto  la  dirección  IP  como  el  puerto 
local etc necesarios para conectar con el servidor 
o http://msdn.microsoft.com/en‐us/library/system.net.ipendpoint.aspx 
 Int32 serverPort: puerto del servidor 
 Socket socket: estructura donde alojar el estado del socket 
o http://msdn.microsoft.com/en‐us/library/system.net.sockets.socket.aspx 
o API de sockets de Berkeley 
 Form vv : Para poder controlar la visualización 
 writeLog log: Lo veremos más adelante, es un callback (delegado en .NET) 

Localice el constructor de la clase ClienteConnection. ¿Qué parámetro recibe? 
¿Qué hace el destructor de la clase ClienteConnection? 

En la clase VistaCliente usaremos el siguiente código para el constructor y los métodos de 
inicialización: 

public delegate void writeLog(string msg);

public partial class VistaCliente : Form


{
ClienteConnection cc = null;
byte[] sendBytes;
byte[] receiveBytes = new byte[2048];

public VistaCliente()
{
InitializeComponent();
}
public void setController(ClienteConnection cc)
{
this.cc = cc;
}

La clase VistaCliente tiene los siguientes atributos: 

 ClienteConnection cc = enlace con el controlador 
 byte[] sendBytes: buffer de datos a enviar al servidor 
 byte[] receiveBytes: buffer de datos con la respuesta del servidor. 

Si echamos un vistazo al código anterior, veremos una declaración similar a un tipo: 

public delegate void writeLog(string msg);

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Consiste  en  un  puntero  a  función,  es  decir,  existe  un  tipo  de  función  llamada  writeLog,  que 
recibe una String y la imprime para que el usuario tenga información a modo de log. 

Interfaz gráfico 
 

A continuación vamos a diseñar el siguiente interfaz gráfico: 

serverNameTextBox
textCheckBoxUserInput

IPTextbox sendDataTextB
serverPort oxUserInput 
button1 
sendButton  updateBinary
ConnectionState Button 
conectButton 
binarySendData
testConnectionButton

responseText

responseBinary

logTextbox

Como puedes comprobar, hay varios controles (cajas de texto, botones, checkbox…) y algunos 
de  ellos  están  introducidos  dentro  de  un  contenedor.  Esto  es  opcional,  en  cualquier  caso,  el 
control que engloba a los demás (como por ejemplo Connection que engloba 3 cajas de texto, 
tres botones y un label) puedes localizarlo en el toolbox como GroupBox. 

Para  que  el  código  que  se  proporciona  en  los  siguientes  apartados  funcione  correctamente, 
debes  asegurarte  de  que  los  diferentes  controles  tienen  la  propiedad  Name  (dentro  del 
apartado Design) que se indica en las cajas de texto apuntadas por las diferentes flechas. 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Función de log 
 

A  continuación  vamos  a  resolver  el  problema  del  log.    En  la  clase  VistaCliente  creamos  la 
función writeLog como se muestra a continuación: 

public void setController(ClienteConnection cc)


{
this.cc = cc;
}
public void writelog(string msg)
{
logTextbox.AppendText(msg);

Dicha función escribe añade texto en la caja de texto logTextbox cuando se la invoca. 

Si  prestamos  atención,  veremos  que  dicho  método  tiene  los  mismos  tipos  definidos  en  la 
declaración del apartado anterior  public delegate void writeLog(string msg) por 
lo que puede usarse como delegado. 

En la clase ClienteConnection, inmediatamente después del destructor, creamos los métodos: 

/* set log */
public void setLogFn(writeLog fn)
{
this.log = fn;
}
/* write log */
public void trace(string msg)
{
StackTrace st = new StackTrace(false);
string caller = st.GetFrame(1).GetMethod().Name;
log(caller + " : " + msg + "\r\n");
}
/* presenta la vista */
public Form getVista()
{
return vv;
}

El método setLogFn recibe un puntero a una función de tipo writeLog y la guarda en el atributo 
log. En método trace recibe una string, contruye un pila de llamadas y accede a la anterior para 
conocer desde que función ha sido llamada la función de log para así incluirlo en el texto de la 
línea  de  log.  Finalmente,  escribe  la  línea  y  le  añade  al  final  un  retorno  de  carro  y  vuelve  al 
comienzo  de  la  línea  (  \r\n  es  equivalente  al  \n  de  C/C++).  La  función  getVista  devuelve  una 
instancia de la clase Form, así tanto el controlador como la vista, permanecen unidos. 

Compruebe como ambas clases VistaCliente y ClienteConnection están enlazadas 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Sustituye el código del main por el siguiente: 

static class Program


{
/// <summary>
/// The main entry point for the application.
/// </summary>
[MTAThread]
static void Main()
{
ClienteConnection cc = new ClienteConnection(new VistaCliente());
((VistaCliente)cc.getVista()).setController(cc);
cc.setLogFn(((VistaCliente)cc.getVista()).writelog);
Application.Run(cc.getVista());

}
}

¿Qué hace el código? 

Comprobando la conectividad 
 

En  este  apartado  vamos  a  comprobar  la  conectividad  de  la  red  antes  de  usarla.  Para  ello,  el 
usuario  dispone  de  un  botón  con  el  mensaje  Test  connection  que  cambiará  el  label 
ConnectionState indicando ok o error dependiendo del problema. 

En  primer  lugar  vamos  a  diseñar  dicha  función.    Para  dar  un  error  detallado  sería  necesario 
interrogar  al  API  de  NDIS  de  Windows  (controla  los  dispositivos  de  red)  de  forma  que  se 
pudiera averiguar si existe conectividad o no, pero lo vamos a hacer desde el nivel más alto, 
desde  sockets.  Lo  primero  que  haremos  será  definir  un  tipo  enumerado  con  los  posibles 
errores o estados: 

public enum connState


{
ok = 0,
dnsProblem = 1,
socketProblem = 2,
dnsAndSocketProblem = 3,
networkErrorOrUnreachable = 4
}

Los posibles estados son: 

1. No hay error 
2. Existe un problema con el DNS (lo cual no significa que no haya conexión) 
3. Problema con la librería de sockets, con independencia del DNS no se puede abrir una 
conexión. 
4. Hay problemas con el DNS y con los sockets 
5. Es posible crear un socket pero probablemente la conexión sólo es local o un firewall 
bloquea el tráfico 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

A continuación, vamos a plantear la estrategia del test: 

1. Tratamos de resolver el nombre www.google.es 
a. Si falla dnsProblem y continuamos 
2. Tenemos o no DNS, pero puede que sólo local 
a. Tratamos de conectar a una IP y si hay éxito continuamos 
b. Tratamos  de  conectar  a  una  IP  y  si  no  hay  éxito  salimos  con  error 
socketProblem o dnsAndSocketProblem. 
3. Tratamos de descargar una página web 
a. Si hay éxito: ok 
b. Si falla: networkErrorOrUnreachable 

Por lo tanto, el código del método para probar la conectividad es el siguiente (inclúyelo como 
métodos de la clase ClienteConnection: 

private connState getError(connState current, connState promoteTo)


{
trace("fetch error");
if (current == connState.ok)
return promoteTo;
if (current == connState.dnsProblem)
if (promoteTo == connState.socketProblem)
{
return connState.dnsAndSocketProblem;
}
else
{
return promoteTo;
}
return promoteTo;

public String getTestConnectionResultString()


{
return testSocketConnection().ToString();
}

private connState testSocketConnection()


{
trace("testing client connection");

connState res = connState.ok;


String testHttp = "GET /index.html HTTP/1.0\n\n";
String httpDoc = null;
int recvLength = 0;
Byte[] SendBytes = Encoding.ASCII.GetBytes(testHttp);
Byte[] RecvBytes = new Byte[1024];
IPAddress testIP = null;
IPEndPoint testEndPoint = null;
Socket testSocket = null;

try
{
testIP = Dns.GetHostEntry("www.google.es").AddressList[0];
testEndPoint = new IPEndPoint(testIP, 80);
}
Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

catch (Exception ex)


{
trace("dns seems to be unavailable");
res = getError(res, connState.dnsProblem);
}
try
{
testIP = Dns.GetHostEntry("163.117.139.128").AddressList[0];
testEndPoint = new IPEndPoint(testIP, 80);
testSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
}
catch (Exception ex)
{
trace("something wrong with sockets");
return getError(res, connState.socketProblem);
}
try
{
testSocket.Connect(testEndPoint);
testSocket.Send(SendBytes, SendBytes.Length,
SocketFlags.None);
recvLength = testSocket.Receive(RecvBytes, RecvBytes.Length,
SocketFlags.None);
}
catch (Exception ex)
{
trace("error connecting");
return getError(res, connState.networkErrorOrUnreachable);
}
httpDoc = Encoding.ASCII.GetString(RecvBytes, 0, recvLength);
//Codificamos la respuesta
trace("finished");
return res;
}
}

Acabas de ver tu primer programa con sockets en .NET: 

¿Cuál es el proceso para abrir una conexión con otro equipo? 
¿Qué NameSpaces se utilizan? 
¿Qué clases? 
¿Notas diferencias con otros APIs? 

Ahora  incorpora  la  funcionalidad  al  botón  de  prueba  (doble  click  y  Visual  Studio  generará  el 
método, el código es el siguiente: 

private void testConnectionButton_Click(object sender,


System.EventArgs e)
{
ConnectionState.Text = cc.getTestConnectionResultString();

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Interactuando con un servidor, preparando los datos 
 

Antes de comenzar a enviar datos al servidor, es necesario prepararlos. El cliente que estamos 
diseñando permite introducir datos de dos formas: 

1. En  modo  texto:  cualquier  letra  introducida  se  codifica  con  ASCII  y  se  envía  salvo  el 
código \n que se traduce a retorno de carro. Esto es interesante por si se quiere usar 
HTTP directamente o para probar un servidor que estamos programando 
a. Para  ello,  el  usuario  introduciría  GET /index.html HTTP/1.0\n\n
directamente en el cuadro de texto sendDataTextBoxUserInput, haría click en 
la  casilla  textCheckBoxUserInput    (mirar  la  figura  del  GUI)  y  luego  en 
updateBinaryButton 
2. Modo  hexadecimal:  Se  introduce  la  información  en  hexadecimal.  Si  se  quiere 
introducir  un  buffer  de  datos  2FC487,  se  teclea  2F  C4  87  y  no  se  marca  la  casilla  de 
modo  texto.  En  cualquier  caso,  siempre  es  necesario  pulsar  el  botón  Update  Binary 
antes de enviar algo al servidor. 

Por  lo  tanto,  necesitamos  un  método  que  prepare  los  datos  del  usuario  para  su  envío  al 
servidor. El método se invoca cuando se pulsa el botón updateBinaryButton. Por tanto, para 
programarlo, haga doble click sobre dicho botón. Analiza el siguiente código y úsalo: 

private void updateBinaryButton_Click(object sender, System.EventArgs


e)
{
sendBytes = null;
binarySendData.Text = "";
String sendDataText = "";
int posicion = -1;
if (textCheckBoxUserInput.Checked &&
sendDataTextBoxUserInput.Text.Length != 0)
{
if (sendDataTextBoxUserInput.Text.IndexOf("\\n") != -1)
{
/* hay retorno(s) de carro (http/telnet) */
String[] subs = sendDataTextBoxUserInput.Text.Split(new
String[] { "\\n" }, StringSplitOptions.None);
for (int i = 0; i < subs.Length; i++)
{
if (subs[i].Equals(""))
sendDataText += "\n";
else
sendDataText += subs[i];
}
}
else
sendDataText = sendDataTextBoxUserInput.Text;

sendBytes = Encoding.ASCII.GetBytes(sendDataText);
}
else
{
if (sendDataTextBoxUserInput.Text.Length >= 2)
{
string delimiter = " ";
Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

byte result = 0x00;


char[] number;
string[] bytesString =
sendDataTextBoxUserInput.Text.Split(delimiter.ToCharArray());
sendBytes = new byte[bytesString.Length];
for (int i = 0; i < bytesString.Length; i++)
{
try
{
number = bytesString[i].ToCharArray();
if (number.Length != 2) throw new Exception("");
byte.TryParse(number[0].ToString(), out result);
sendBytes[i] = (byte)(result << 4);
byte.TryParse(number[1].ToString(), out result);
sendBytes[i] |= (byte)result;
}
catch (Exception ex)
{
cc.trace("Hay un error en el formato, recuerda: si
es binario, debes escribir, por ejemplo, 12 34 AB, siendo estos
numeros hexadecimales");
}

}
}
}

if (sendBytes != null)
for (int i = 0; i < sendBytes.Length; i++)
{
binarySendData.AppendText(sendBytes[i].ToString("x") + "
");
}

¿Qué hacen los métodos de la clase String llamados Split, IndexOfAny y Equals? 
¿Qué hace Encoding.ASCII.GetBytes? 
¿Cómo se comprueba si los datos son texto o hexadecimales? 
¿Cómo se comprueban los errores de formato en el caso hexadecimal? 
Comprueba si todos los errores se corrigen 
Utiliza la depuración línea por línea para ver qué hace cada parte del código. Lo 
mejor es poner un breakpoint al comienzo del método y luego ir línea por línea con 
F10. 

Interactuando con un servidor, iniciando la conexión 
 

Del apartado de prueba de conectividad, habrás aprendido a abrir un socket, ahora lo haremos 
paso por paso.  

Funcionalidad del botón Resolve 
 

Cuando se pulsa el botón Resolve (button1), debe usarse este código: 

private void button1_Click(object sender, EventArgs e)


Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

{
if (serverNameTextBox.Text.Length > 0)
{
IpTextbox.Text =
cc.getServerIP(serverNameTextBox.Text).ToString();
}
else
cc.trace("por favor, incluye el nombre del servidor");

Por lo tanto, puede comprobarse que la funcionalidad está en la clase ClienteConnection pese 
a que los resultados (IP traducida) se muestren en la caja de texto IpTextbox. 

Utiliza los siguientes métodos dentro de la clase ClienteConnection: 

public IPAddress getServerIP(String serverName)


{
return Dns.GetHostEntry(serverName).AddressList[0];

}
/* dada una ip o nombre de maquina, cambia la direccion del servidor
*/
public void setServerIP(String serverIPString)
{
dirServidor = Dns.GetHostEntry(serverIPString).AddressList[0];
}
public void setServerPort(String port)
{
Int32 result = 0;
try{
Int32.TryParse(port, out result);
serverPort = result;
}catch(Exception ex)
{
trace("es correcto el puerto?");
}

Razona sobre lo que hace cada uno de ellos. 
¿Cuáles cambian el valor de atributos de la clase ClienteConnection? 
Pruébalo con www.google.es y con www.uc3m.es 
Claramente google usa balanceo de carga con DNS (puedes comprobarlo desde un 
intérprete de comandos (cmd) con el comando nslookup www.google.es 
 Si lo ejecutas varias veces puedes ver cómo cambian el grupo de IPs que 
proporcionan el servicio de google. 
 ¿Por qué el programa devuelve sólo la primera?. ¿Cómo lo cambiarías para 
que te diera de las tres aleatoriamente? 

Funcionalidad del botón connect! (conectButton) 
 

Este  método  debe  proporcionar  al  controlador  todos  los  datos  de  dirección  del  servidor, 
puerto  necesario  para  conectar  y  además  realizar  control  de  errores.  Utiliza  el  siguiente 
código: 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

private void conectButton_Click(object sender, EventArgs e)


{
try
{
if (IpTextbox.Text.Length != 0 &&
serverNameTextBox.Text.Length != 0 && serverPort.Text.Length != 0)
{
cc.setServerIP(IpTextbox.Text);
cc.setServerIP(serverNameTextBox.Text);
cc.setServerPort(serverPort.Text);
cc.connect();
}
else
throw new Exception();
}
catch (Exception ex)
{
cc.trace("por favor, comprueba la dirección IP o el nombre de
servidor");
}

El  único  método  que  quedaría  por  programar  sería  connect()  dentro  de  la  clase 
ClienteConnection. Este método debe hacer lo siguiente (para nuestros propósitos): 

1. Comprobar si el socket es nulo. 
a. Si es null, lo creará 
b. Si no, comprueba si está conectado, y en ese caso lo desconecta 
2. Crea un objeto IPEndPoint con la información necesaria 
3. Crea un socket  
4. Conecta 

Analiza el siguiente código y úsalo en la aplicación: 

/* conecta al servidor */
public void connect()
{
try
{
if (socket != null)
if (socket.Connected)
{
trace("cerrando antiguas conexiones...");
socket.Disconnect(true);
}
trace("creando el endpoint...");
endPointServidor = new IPEndPoint(dirServidor, serverPort);
trace("creando el socket...");
socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
trace("conectando");
socket.Connect(endPointServidor);
}
catch (Exception ex)
{
trace("error en la conexión" + ex.Message);
}

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Interactuando con un servidor, enviando y recibiendo datos 
 

Finalmente  debemos  dar  funcionalidad  al  botón  send  (sendButton)  para  que,  a  través  de  la 
clase ClienteConnection, envíe los datos al servidor. 

Utiliza el siguiente código para el botón send: 

private void sendButton_Click(object sender, EventArgs e)


{
int recibido = cc.sendReceive(sendBytes, ref receiveBytes);
cc.trace("recibidos " + recibido + " bytes.");
responseBinary.Text = "";
for (int i = 0; i < recibido; i++)
{
responseBinary.AppendText(receiveBytes[i].ToString("X"));
}
String respuesta = Encoding.ASCII.GetString(receiveBytes, 0,
recibido); //Codificamos la respuesta
responseText.Text = "";
responseText.AppendText(respuesta);
}

¿Qué hace este método? 
¿Qué elementos de la GUI están involucrados? 

 
Utiliza el siguiente código para la clase ClienteConnection: 

public int sendReceive(byte[] sendBytes, ref byte[] receiveBytes)


{
try
{
int bytes_returned = 0;
/* enviamos los bytes */
socket.Send(sendBytes, sendBytes.Length, SocketFlags.None);
bytes_returned = socket.Receive(receiveBytes,
receiveBytes.Length, SocketFlags.None);
return bytes_returned;
}
catch (SocketException sExec)
{
trace("Error: " + sExec.Message);
}
return 0;
}
 

¿Sabías que C#, a diferencia de Java, permite parámetros por referencia en los 
métodos? 
¿Qué palabra reservada crees que le indica al compilador que es por referencia y no 
por valor? 
Haz peticiones HTTP a varios servidores, prueba que todo funcione bien. 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

   

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

Práctica 4. Servidor en .NET 
 

En esta práctica vamos a crear un sencillo servidor para atender las peticiones de los clientes. 
Para ello crearemos una aplicación de consola: 

Y usaremos el siguiente código como base para implementar el protocolo que comentaremos 
a continuación: 

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace ComputacionRed.Sockets.Servidor
{
class Program
{
static void Main(string[] args)
{
IPAddress direc =
Dns.GetHostEntry("localhost").AddressList[0];

IPEndPoint Ep = new IPEndPoint(direc, 12345);


Socket socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
socket.Bind(Ep);
Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

socket.Listen(100);

Socket handler = socket.Accept();


byte[] bytes = new byte[1024]; //Declaramos un array de bytes
de longitud 1024
int count;
String data = ""; //Declaramos data, que sera donde se
almacenaran los datos

try
{
do
{
count = handler.Receive(bytes);
data = System.Text.Encoding.ASCII.GetString(bytes, 0,
count);

/* Procesado de los mensajes del protocolo aqui */

bytes = System.Text.Encoding.ASCII.GetBytes(response);
handler.Send(bytes,
System.Text.Encoding.ASCII.GetByteCount(response), SocketFlags.None);

} while (data != "Exit");

Console.WriteLine("Conexion finalizada");

handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception ex)
{
Console.WriteLine("Excepcion" + ex.Message);
}
}
}

}
 

Analiza las líneas de código suministradas 

Ahora debes crear un protocolo con el siguiente formato. Lo que se enviarán serán cadenas de 
texto con la estructura $Comando$Valor. El protocolo es sin estado y los comandos y sus 
posibles valores son: 

 Hello: Debe ir acompañado del nombre del cliente (ej. $Hello$Dani ). El servidor debe 
responder $Hello$NiceToSeeYouAgain 
 Echo: Debe ir acompañado de un texto de longitud variable (ej. $Echo$Texto a repetir). 
El servidor debe contestar $Echo$ + el texto mandado por el cliente 
 Date: No tiene valor, se envía únicamente el comando. El servidor debe responder 
$Date$Dia/Mes/Año 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 
Apuntes de Computación en la Red. Prácticas demostrativas de .NET 

 Time: No tiene valor, se envía únicamente el comando. El servidor debe responder 
$Date$Hora:Minuto 
 Random: No tiene acompañamiento. El servidor debe devolver 20 bytes aleatorios. 
 Exit: finaliza la conexión 

Para hacerlo, puede necesitar las siguientes Clases/métodos (usa google y el código 
proporcionado hasta ahora para conseguirlo): 

1. System.DateTime.Now 
2. String.Split 
3. System.Text.Encoding.ASCII.GetBytes 
4. Random 
5. System.Text.Encoding.ASCII.GetByteCount 

Cambia ahora a protocolo con sesión, usa el mensaje de Hello para ello. 

Cliente en consola 
 

Ahora que has probado el servidor, crear un cliente basado en consola que interactúe con el 
servidor, esta vez, sin ayuda… 

Daniel Díaz Sánchez, Andrés Marín López, Florina Almenarez (http://pervasive.it.uc3m.es) 
Departamento de Ingeniería Telemática. Universidad Carlos III de Madrid. 
 

También podría gustarte