Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

37
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. 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.

Transcript of Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

Page 1: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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. 

Page 2: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

 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… 

 

Page 3: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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: 

 

 

 

 

 

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

 

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 

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); } } 

public static int Main(),

public static void Main(),

public static void Main(string[] args)

public static int Main(string[] args) 

Page 4: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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: 

Page 5: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

 

   Automático: 

Variables  en 

uso  en  cada 

momento 

Variables 

locales: 

Variables  en 

el método 

Pila de llamadas Ventana  de 

comandos… 

Línea  donde  se 

encuentra  la 

ejecución 

Page 6: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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. 

Page 7: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

 

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 */ } } } 

Page 8: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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.  

 

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 

using System; using System.Collections.Generic; using System.Text; namespace Utilidades.UtilidadLog { public class Log { } }  

Page 9: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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(); }

Page 10: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

 

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. 

 

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"); } } } }  

Page 11: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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: 

Page 12: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

 

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: 

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(); } } } 

Page 13: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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 

Page 14: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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. 

Page 15: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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): 

 

 

 

 

 

 

 

 

 

 

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. 

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()); } } } 

Page 16: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

 

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

a la pantalla. 

 

Page 17: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

 

 

Añade varios elementos: 

Page 18: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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 

Page 19: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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. 

 

   

Page 20: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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:

Page 21: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

 

  /* 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(); } } } 

Page 22: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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 ... */ } }

Page 23: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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);

Page 24: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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: 

 

 

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. 

 

serverNameTextBox

textCheckBoxUserInput

sendDataTextB

oxUserInput 

updateBinary

Button 

binarySendData

responseText

responseBinary

logTextbox

testConnectionButton

ConnectionState

sendButton 

button1 

serverPort

IPTextbox

conectButton 

Page 25: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

 

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 

 

Page 26: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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 

Page 27: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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); }

Page 28: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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(); }

Page 29: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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 = " ";

Page 30: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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)

Page 31: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

{ 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: 

Page 32: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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); }

Page 33: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

}

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. 

Page 34: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

 

 

 

   

Page 35: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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);

Page 36: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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 

Page 37: Práctica 1. Introducción a .NET, aplicaciones básicas, namespaces ...

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. 

 

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…