sábado, 29 de diciembre de 2012

Trabajando con tipos binarios BLOB (Binary Large Object ) en PostgreSQL.

En el estándar SQL están definidos dos tipos de datos para guardar grandes cantidades de información, el CLOB (CHARACTER LARGE OBJECT) que se utiliza para información de tipo texto y el BLOB (BINARY LARGE OBJECT).

El tipo de datos CLOB se representa en la base de datos como un registro con una gran cantidad de información de tipo carácter, estos caracteres pertenecen al conjunto de caracteres definidos por la base de datos (generalmente ASCII) siendo de un solo byte por lo que se utiliza para guardar archivos de texto como por ejemplo los archivos XML. Por su parte el tipo de datos BLOB se representa como un registro de una gran cantidad de información binaria sin estructura distribuida de forma aleatoria por lo que es ideal para archivos binarios como los mapas, las gráficas, y todos los archivos multimedia.

Trabajando tipos de datos BLOB con funciones predeterminadas de PostgreSQL

PostgreSQL proporciona el soporte para tipos de datos BLOB mediante las funciones predeterminadas: lo_import() y lo_export(), las cuales importan y exportan archivos desde el sistema de archivos hacia la base de datos y viceversa. Para ejemplificar el uso de estas funciones tenemos una tabla llamada Books con el siguiente script SQL:

Es esta tabla la columna picture tiene un tipo de dato oid el cual es un identificador que se utiliza como referencia hacia la tabla de sistema pg_largeobject la cual almacena el objeto binario en una o más filas, por lo que la columna picture almacena únicamente el apuntador hacia la información del objeto binario no el objeto binario en si. Como ejemplo agregamos un registro a la tabla, importando la imagen desde el sistema de archivos hacia la base de datos con la función: lo_import()

Ahora recuperamos el registro obteniendo la imagen desde la base de datos hacia el sistema de archivos con la función lo_export().

Las funciones lo_import() y lo_export() son ejecutadas directamente por el servidor de PostgreSQL por lo que la ruta completa del archivo debe tener los permisos correspondientes para ser accesibles desde el servidor, es necesario que el usuario de PostgreSQL tenga el rol de superuser de PostgreSQL (no confundir con el root de Linux).

viernes, 14 de diciembre de 2012

Algoritmo Genético para el TSP (Traveling Salesman Problem) con Monodevelop utilizando C#

La computación evolutiva es una parte de la inteligencia artificial donde se agrupan diferentes técnicas adaptativas enfocadas a encontrar las mejores soluciones para resolver problemas de optimización, estas técnicas parten de una de las principales ideas que existen en la teoría de la evolución biológica propuesta por Charles Darwin, la selección natural es el proceso histórico de transformación de unas especies en otras especies descendientes e incluye la extinción de la gran mayoría de las especies que han existido, lo que es sin duda un problema de optimización además de que muchos de los términos que utiliza la computación evolutiva son tomados de la biología, con la advertencia de que se son usados para representar más o menos la misma idea biológica lo que no equivale a que sean iguales.

La computación evolutiva se compone por las siguientes técnicas:

  1. Programación evolutiva: Son una estrategia de optimización estocástica hacen un énfasis específico en los operadores genéticos tal y como se observan en la naturaleza.
  2. Estrategias evolutivas: Esta técnica esta básicamente enfocada hacia la optimización. En esencia son métodos estocásticos con paso adaptativo, que permiten resolver problemas. A este método se le han agregado procedimientos propios de la computación evolutiva, que lo han convertido en un paradigma más de dicha metodología.
  3. Algoritmos genéticos: Usan métodos que tienen analogía en la selección natural y la evolución.
Entre los usos de la computación evolutiva se encuentran la planificación, el diseño de sistemas, la simulación, el reconocimiento de patrones, el control y la clasificación de datos.

La alternativa para una solución de problemas de planificación y de optimización donde la mayoría están se ubican dentro de la categoría de los problemas NP los cuales no pueden ser resueltos usando las técnicas convencionales y solo pueden ser atacados desde las técnicas de computación evolutiva donde el dominio de esos problemas le corresponden a los algoritmos genéticos (John H. Holland, 1975) 

Como ejemplo de este tipo de aplicaciones me encontré en este web site (http://www.heatonresearch.com) un Applet Java, que utiliza algoritmos genéticos para obtener una solución optima al problema del agente viajero (Traveling Salesman Problem), en el mismo web site el autor nos hace un resumen del problema.

Pues bien como un ejercicio de aprendizaje, traduje el código del applet de Java a C# como un proyecto de Monodevelop utilizando Winforms, a continuación algunas screenshots y el código fuente del proyecto. He de aclarar que debido a la falta de tiempo hice casi copia tal cuál del código, modificando las partes de Java que el compilador me marcaba como errores.

Inicio de la aplicación

Aplicación en ejecucción

Resultado de la aplicación

En su web site el autor Jeff Heaton además del código fuente del applet, ofrece libros acerca de inteligencia artificial y de programación con Java y C#.

martes, 2 de octubre de 2012

Utilizando secuencias (sequences) en PostgreSQL con C# .

Con frecuencia en un buen diseño de bases de datos es necesario que las tablas tengan al menos un identificador único para poderlas relacionar con otras, siguiendo las recomendaciones de las conocidas reglas de Codd para el modelo relacional de bases de datos.Para cumplir con este requerimiento podemos fijarnos en la entidad que representa cada tabla y seguir la especificación del identificador único que le correspondería según nos dicten las reglas del negocio o el tipo de sistema que vamos a construir.

Hay casos en donde la tabla no tiene una entidad definida sino sirve únicamente como tabla de soporte para una relación muchos a muchos, como un catálogo o un listado de parámetros para el sistema, en estos casos donde no se tiene una especificación definida para asignar un identificador único lo más recomendado es utilizar una serie o un contador como valor para ese identificador.

PostgreSQL proporciona unos objetos llamados secuencias (sequences) que sirven para crear contadores o series, las secuencias son objetos de bases de datos al mismo nivel que las tablas, vistas, triggers o funciones.

Aunque pueden crearse contadores y series de forma manual esto no será tan eficiente como los objetos sequence que nos proporciona PostgreSQL ya que mejoran el desempeño de la base de datos sobretodo en sistemas multiusuario. La forma automática de crear una secuencia es utilizar el tipo de dato serial en una columna, como se muestra a continuación con el siguiente script para una tabla llamada Publishers.

Al ejecutar este script se crean dos objetos: la secuencia (sequence) y la tabla (en ese orden), como lo muestra la pestaña messages de pgadmin al finalizar la ejecución del script.

Ahora creamos una función plpgsql con la que agregaremos los registros a la tabla, en esta función establecemos los valores mediante parámetros para cada una de las columnas, excepto claro el identificador (columna publisherid), ya que de ese valor se encargará la secuencia.

Ahora con el siguiente programa en C# probaremos la secuencia agregando algunos registros e imprimiendo sus identificadores en la consola.

Compilamos el programa con el siguiente comando.

$ gmcs -r:/home/martin/lib/Npgsql2.0.11.94/Mono2.0/bin/Npgsql.dll,System.Data Main.cs

Al ejecutar el programa, se mostrarán los registros agregados y los valores que les asigno la secuencia como identificador.

También podemos crear una secuencia (sequence) de forma manual siguiendo la sintaxis:

create sequence [name] start with [number] increment by [number]

De manera predeterminada las secuencias comienzan en el número 1 al menos no se indique con el comando start with. Por ejemplo creamos una secuencia que se incremente de 6 en 6

Test=# CREATE SEQUENCE my_first_sequence_seq INCREMENT BY 6;

Para acceder a los valores de la secuencia lo hacemos con un SELECT y la función nextval() como se muestra a continuación:

Observamos que la secuencia comienza en 1 e incrementa de 6 en 6.
Para acceder al valor actual de la secuencia lo hacemos con la función currval() como se muestra a continuación:

Para establecer un nuevo valor en la secuencia utilizamos la función setval()

Por último podemos eliminar la secuencia creada con el comando:

DROP SEQUENCE [name]

Como se muestra a continuación, en la siguiente imagen:

jueves, 6 de septiembre de 2012

Utilizando parameterized commands (comandos con parámetros) de ADO.NET en PostgreSQL con GTK#

Para complementar el tema del post anterior, como un segundo ejemplo mostramos un formulario GTK# que utiliza una función PL/SQL, en donde además de los parámetros de entrada se establecen dos parámetros de salida, los cuales una vez de ejecutada la función devuelve los valores número de referencia y la fecha actual, que el formulario GTK# muestra en un mensaje.
Para preparar el ejemplo, creamos una base de datos llamada Test con una tabla llamada workitems en donde la función creará un nuevo registro.
Aquí el código de la tabla:



A continuación el código de la función.



Esta función utiliza la función createrefnum(id) utilizada en la primera parte de este tutorial.
En esta función los parámetros de salida se especifican con la palabra reservada OUT junto a los parámetros de entrada en los argumentos, inmediatamente después del la declaración del nombre, como se muestra el siguiente fragmento del código.



create or replace function usp_createworkitem(out nref varchar,varchar,varchar,varchar,
varchar,out creationDate timestamp)

En este ejemplo debemos de tener una solución en MonoDevelop con dos tipos de proyectos: uno de tipo library en donde se pondrán las siguientes clases:
WorkItem.cs : representa la clase de transporte de datos o POCO.
MessageDAC.cs: que representa la clase de acceso a PostgreSQL.

El otro es un proyecto tipo GTK# que contiene las clases Main.cs y MainWindow.cs correspondientes a la GUI del formulario y al manejo de eventos.
La solución deberá de verse como en la siguiente imagen:


El diseño del formulario queda como en la siguiente imagen:



A continuación el código de las clases de la solución.
Aquí el código de las clase Workitem.cs



Aquí el código de la clase MessageDAC.cs



Aquí el código de la clase MainWindow.cs



En la clase MessageDAC se encuentra el código en donde ejecutamos la función, para que se ejecute correctamente debemos establecer la propiedad CommandType de la clase NpgsqlCommand con el valor de la enumeración CommandType.StoredProcedure.


cmd.CommandType = CommandType.StoredProcedure;

Entonces creamos los parámetros de entrada y de salida, para los de salida se crea un NpgsqlParameter por cada uno y se establece su propiedad Direction con la enumeración ParameterDirection.Output, es importante no olvidar agregarlos a la enumeración Parameters del NpgsqlCommand.


NpgsqlParameter nref = new NpgsqlParameter("nref",NpgsqlDbType.Varchar);
nref.Direction = ParameterDirection.Output;
cmd.Parameters.Add(nref);
cmd.Parameters.Add("Title",NpgsqlDbType.Varchar).Value = wk.Title;
cmd.Parameters.Add("AssignedTo",NpgsqlDbType.Varchar).Value = wk.AssignedTo;
cmd.Parameters.Add("Area",NpgsqlDbType.Varchar).Value = wk.Area;
cmd.Parameters.Add("Reason",NpgsqlDbType.Varchar).Value = wk.Reason;
NpgsqlParameter created = new NpgsqlParameter("creationDate",NpgsqlDbType.Timestamp);
created.Direction = ParameterDirection.Output;
cmd.Parameters.Add(created);


Después de ejecutar el comando para llamar la función obtenemos el valor de regreso, haciendo referencia por su nombre de la enumeración Parameters.


wk.Numref = cmd.Parameters["nref"].Value.ToString();
wk.Created = Convert.ToDateTime(cmd.Parameters["creationDate"].Value);


Al compilar y ejecutar el formulario se verá como en la siguiente imagen:


Al introducir los valores y presionar el botón OK se ejecutará el llamado a la función agregando el registro y devolviendo los valores de salida, que se mostrarán con un mensaje como se ve en la siguiente imagen:


Si todo se ejecuto correctamente, podemos consultar el registro ejecutando el siguiente comando desde una terminal:



$ psql Test –c “Select * from workitems” - A

viernes, 31 de agosto de 2012

Utilizando parameterized commands (comandos con parámetros) de ADO.NET en PostgreSQL con C#.


Aunque este tutorial se centra en PostgreSQL, utilizo la clase genérica
DbCommand, ya que estos conceptos son aplicables a otros manejadores de bases de datos como Oracle o SQL Server, únicamente reemplazando las clases DbCommand y DbParameter por las clases específicas de ADO .NET para estas bases de datos.


La clase DbCommand de ADO .NET nos proporciona la capacidad de ejecutar comandos parametrizados, lo que nos permite pasar información en tiempo de ejecución a los store procedures o comandos SQL que nuestra aplicación .NET envié hacia la base de datos.
Estos parámetros se clasifican por su valor dentro de la enumeración ParameterDirection:


  • Input: Son el tipo predeterminado, envía los valores hacia la base de datos, es posible tener múltiples parámetros de entrada.

  • Output: Similar a los parámetros Input, solo que regresan los valores de retorno una vez que el comando es ejecutado, es posible tener múltiples parámetros de salida.

  • InputOutput: El parámetro es capaz de enviar y recibir un valor después de que el comando es ejecutado.

  • ReturnValue: El parámetro representa el valor de retorno de la función.


El uso de comandos parametrizados nos ofrece los siguientes beneficios:


  • Nos permite definir el tipo de dato del parámetro.

  • Evita la concatenación de sentencias SQL en el código, con lo que disminuye el riesgo de un ataque SQL Injection.

  • Obtenemos un mejor rendimiento, las consultas pre-compiladas tienen un mejor desempeño al ejecutarse ya que el plan de ejecución es reutilizado para la misma consulta en vez construirlo repetidamente en cada ejecución como ocurre con las consultas SQL literales.

  • Los parámetros son revisados y validados para comprobar que no exista código malicioso, una de esas validaciones es la longitud, por ejemplo si el parámetro especifica una longitud de 50 caracteres, entonces solo 50 caracteres serán aceptados.


DbCommand tiene la propiedad Parameters que representa la colección de parámetros que están asociados al comando SQL. Estos parámetros son representados por el objeto DbParameter el cual tiene las siguientes propiedades:

    DbType: Representa el tipo de dato de la fuente de datos como un tipo CLR.
    Direction: Indica si el parámetro es de entrada, de salida o bidireccional.
    IsNullable: Indica si el parámetro acepta valores nulos.
    ParameterName: Representa el nombre del parámetro.
    Size: Representa la longitud del parámetro.
    Value: Obtiene u establece el valor del parámetro.

Como ejemplo un programa C# que muestra el uso de los comandos parametrizados llamando a una función de PL/pgSQL en PostgreSQL que realiza una concatenación de un número aleatorio, el año actual y el parámetro de entrada para crear un número distinto cada vez que se ejecute.
El código PL/pgsql de la función es el siguiente:


El resultado de la ejecución de la función es:

A continuación un ejemplo en C# en donde se muestra el uso de los parámetros ejecutando la función anterior con su parámetro de entrada (input) y recibiendo el valor de retorno.



Este ejemplo en MonoDevelop puede construirse como una aplicación de consola, agregando las refrencias al ensamblado Npgsql, como se muestra en la siguiente imagen:


La salida de la ejecucción de este programa es:

Si se ejecuta desde MonoDevelop la salida es:

domingo, 29 de julio de 2012

Power Shell para Mono

Power Shell es el más reciente intérprete de comandos o CLI (Command Line Interface) para ambientes Windows similar a la consola de MS-DOS pero a diferencia de esta; Power Shell es además un lenguaje de guiones (Scripting Language) con derecho propio para competir con las opciones de cualquier shell en las plataformas UNIX/Linux.
Si retomamos una de las definiciones clásicas de lo que es un Shell:


"El Shell lee las ordenes y las interpreta como peticiones de ejecución de un programa o programas, por esta característica al shell se le denomina interprete de comandos, aquí el Shell es un lenguaje de programación."

tomado del libro UNIX System V Versión 4, Kenneth H. Rosen & Richard R. Rosinski.


Uno de los objetivos de Power Shell es llenar el vacío que siempre ha caracterizado a los sistemas Windows en cuanto a tener una consola de comandos medianamente funcional y poderosa ya que en este aspecto el Shell en los sistemas UNIX/Linux nunca han tenido ni cercanamente una competencia en el MS-DOS.
Dentro de las características de Power Shell tenemos las siguientes:


  • Esta basado en el Korn Shell por lo que hasta cierto la funcionalidad de este Shell es compatible con Power Shell.

  • Cumple con el estándar POSIX IEEE 1003.2

  • Es un scripting language que se agrega a los lenguajes de programación de Microsoft.

  • Utiliza el modelo de objetos de .NET para la representación de datos.


Pues bien en la página http://pash.sourceforge.net/ hay una versión Open Source de Power Shell la cual puede usarse con Mono.
Una vez que se han descargado los binarios desde la pagina se ejecuta el comando:

$ mono Pash.exe

Enseguida aparecerá la consola de Power Shell como en la siguiente imagen:


sábado, 23 de junio de 2012

Manuales acerca de PostgreSQL

Uno de los aspectos importantes para el desarrollo de aplicaciones corporativas en .NET o Mono es conocer una sistema manejador de base de datos (DBMS) a un buen nivel, en el caso de los ambientes Windows la opción predeterminada para los desarrolladores .NET es SQL Server,aunque también existen opciones open source para esa plataforma, una buena parte de las herramientas de base de datos de .NET es concebida en inicio para ese producto.
Para los ambientes Linux existen DBMS comerciales y open source igualmente buenas, pero hay un DBMS en particular que la mayoría de las ocasiones debemos de tener en cuenta sobretodo por sus características y este sin duda es PostgreSQL, ya por algo su lema es: "The world's most advanced open source database" (la base de datos open source más avanzada del mundo).
Pues bien, aquí pongo unos documentos que nos apoyarán en el conocimiento de este DBMS.

lunes, 18 de junio de 2012

Envio de e-mails vía SMTP con GTK# y Monodevelop.

Uno de los requerimientos más comunes para las aplicaciones .NET es el envío de E-mails o correos electrónicos, entre los ejemplos mas usuales para este tipo de requerimiento se encuentran el envío automático automático de boletines electrónicos, notificaciones de eventos, bitácora del sistema, solicitudes de reunión, envío de archivos adjuntos entre otros. .NET nos proporciona los ensamblados System.Net.Mail y System.Net.Mime, los cuales contienen todas las clases e interfaces necesarias para habilitar este tipo de requerimiento en cualquier aplicación .NET, a continuación describimos los elementos más importantes de estos ensamblados:

  • MailMessage:
  • Representa un mensaje de correo electrónico, esta clase tiene todas las propiedades del mensaje por ejemplo: tema del mensaje, destinatario, destinatarios, remitente,cuerpo entre otras.
  • MailAdress:
  • Representa una dirección de correo electrónico, esta clase ya implenta la lógica para validar que el formato sea correcto.
  • ContentType:
  • Representa la cabecera del protocolo MIME
  • AlternateView:
  • Representa una vista alternativa del mensaje en un formato diferente al predeterminado, por ejemplo HTML ó Calendar.
  • SmtpClient:
  • Esta clase se encarga de enviar el mensaje, aquí se establecen los parámetros de configuración del servidor SMTP, como: numero de puerto, usuario, password, SSL entre otros.

Como ejemplo de la utilización de estas clases, mostramos un formulario GTK# en Monodevelop que recibe los parámetros de configuración de un servidor SMTP, crea un mensaje de correo electrónico y lo envía hacia el o los destinatarios, utilizando dos clases: EMailMessage y SendMail.

El formulario en vista de diseño de MonoDevelop.


El código fuente de la clase EmailMessage


El código fuente de la clase Sendmail
<--Code Sendmail-->

<--Code Sendmail-->
El código fuente del formulario GTK#.
using System;
using Gtk;
using TestMail;
using System.Collections.Generic;

public partial class MainWindow : Gtk.Window
{
public MainWindow () : base(Gtk.WindowType.Toplevel)
{
Build ();
}

protected void OnDeleteEvent (object sender, DeleteEventArgs a)
{
Application.Quit ();
a.RetVal = true;
}
protected virtual void OnBtnSubmitClicked (object sender, System.EventArgs e)
{
try{
SendMail sendMail = null;
var email = new EMailMessage(txtSubject.Text,
                                  txtFrom.Text,
                                  GetAddresses(),
                                  txtDescription.Buffer.Text,
                         chkIsHtml.Active);
if(chkCredentials.Active)
sendMail = new SendMail(txtHost.Text,Convert.ToInt32(txtPort.Text),chkEnableSSL.Active);
else
sendMail = new SendMail(txtHost.Text,Convert.ToInt32(txtPort.Text),chkEnableSSL.Active
                            ,txtUserName.Text,txtPassword.Text);
sendMail.Send(email);
ShowMessageBox("Email Sent");
}catch(Exception ex){
ShowMessageBox(ex.Message);
}
}

void ShowMessageBox(string msg){
using (Dialog dialog = new MessageDialog (this,
      DialogFlags.Modal | DialogFlags.DestroyWithParent,
      MessageType.Info,
      ButtonsType.Ok,
      msg)) {
dialog.Run ();
dialog.Hide ();
}
}

List<string> GetAddresses() {
var resp = new List<string>();
foreach (string s in txtTo.Text.Split(','))
resp.Add(s);
return resp;
} 
protected virtual void OnBtnQuitClicked (object sender, System.EventArgs e)
{
Application.Quit();
} 

protected virtual void OnChkCredentialsToggled (object sender, System.EventArgs e)
{
tblCredentials.Visible = !chkCredentials.Active;
}
}

Básicamente el envió de correos electrónicos consiste de dos pasos: Primero la creación del mensaje con sus adjuntos si es que los hubiese, de esta responsabilidad se encarga la clase EMailMessage, la cuál es una clase derivada de MailMessage y se establecen todos sus parámetros en el constructor.

public EMailMessage (string subject,string fromField,List to,string body,
                       bool isBodyHtml)
 {
 Subject = subject;
 From = new MailAddress(fromField);
 foreach(string item in to) To.Add(new MailAddress(item));
 IsBodyHtml = isBodyHtml;
 if(IsBodyHtml)
  Body = GetHTMLContent(body);
 else
  Body = body;
 }

Como segundo paso, el envió del mensaje mediante un servidor SMTP. La clase Sendmail se ocupa de esta responsabilidad solicitando los parámetros de configuración del Server.

public SendMail(string server,int port,bool enableSSL){
 Server = server; 
 Port = port;
 EnableSSL = enableSSL;
 }
 public SendMail(string server,int port,bool enableSSL,string username,string password): 
 this(server,port,enableSSL){
 UserName = username;
 Password = password;
 Credentials = true;
 }

Y después envía el mensaje con el siguiente método:

public void Send(MailMessage msg){
 SmtpClient = new SmtpClient(Server,Port);
 SmtpClient.EnableSsl = EnableSSL;
 //DO NOT use: this property throws a Exception
 //SmtpClient.UseDefaultCredentials = true;
 if(Credentials){
 SmtpClient.UseDefaultCredentials = false;
 SmtpClient.Credentials = new NetworkCredential(UserName,Password);
 }
 ServicePointManager.ServerCertificateValidationCallback = 
     delegate(object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) 
     { return true; };
 SmtpClient.Send(msg);
 }

En este método primeramente establecemos la configuración del servidor, indicamos si se usa o no una conexión segura, después en caso de requerir identificación establecemos el usuario y la contraseña, después utilizamos el delegado ServerCertificateValidationCallback de la clase estática ServicePointManager para la validación del certificado del servidor.
Luego de compilar, ejecutamos y probamos la aplicación utilizando el servidor de correo Gmail en cuyo caso establecemos la configuración como: Host: smtp.gmail.com
Port: 587
Username: [user name]@gmail.com
EnableSSL: true

Si el envío resulta exitoso la aplicación nos mostrará el siguiente mensaje:

De forma predeterminada el mensaje se envia en texto plano, para enviar el mensaje en HTML, habilitamos el checkbox para activar la propiedad IsBodyHtml y recibir el mensaje en este formato.

Tambien podemos utilizar un servidor local SMTP en caso de que nuestra distribución OpenSuse tenga instalados Postfix o Sendmail.

En el caso de no usar autentificación existe la propiedad UseDefaultCredentials que funciona en el Framework .NET de Microsoft, no así en el Framework Mono, si la utilizamos, Mono lanzará una excepción como se muestra en la siguiente imagen:

martes, 22 de mayo de 2012

Serialización de Objetos en .NET

Serialización se denomina al proceso de transferir un objeto que se ejecuta en la memoria de un programa hacia un medio de persistencia para conservar su estado y sus datos en ese momento, para deserializarlo o bien volver a recuperarlo cuando se considere conveniente, en algunos casos el mecanismo de serialización/deserialización es más práctico que utilizar las clases readers/writers para persistir.

En .NET existen tres tipos de serialización: Binaria, XML y Soap los cuales nos permiten cierta independencia del medio de transporte. La serialización binaria es la más sencilla, óptima y ofrece un mejor rendimeinto que los otros tipos de serialización, aunque no es recomendada si los objetos serializados requieren ser transportados hacia otros sistemas operativos, lenguajes de programación o arquitecturas que no sean .NET, por lo que para el tema de interoperabilidad las mejores opciones son la serialización de objetos en XML ó SOAP.

La serialización en .NET consiste básicamente en dos responsabilidades: una es la responsabilidad del objeto serializable el cuál indica los miembros a serializar y la otra es la del serializador/deserializador la cuál se encarga de transferir el objeto hacia o desde un medio de persistencia. Supongamos una aplicación encargada de administrar una colección de libros, esta aplicación tiene una clase Author la cuál queremos serializar, primeramente marcamos la clase con el atributo:

[Serializable]
Hay que tener presente que no todas variable de instancia puede ser serializables, por ejemplo los metodos o variables estáticas no lo son, al contrario de los tipos primitivos, los arreglos y los objetos string los cuales son serializables de forma predeterminada. Siempre hay que asegurarse que los objetos y su clase base sean serializables antes de asumir que cualquier tipo de objeto puede ser serializado. Si encontramos o necesitamos que una propiedad del objeto no sea serializable la marcamos con el atributo:
[NonSerialized]
A continuación mostramos el código fuente de una aplicación que muestra la serialización y deserialización binaria de una relación de objetos mediante la utilización de la clase BinaryFormatter. Los archivos que componen la aplicación son: Author, Book , Publisher y la clase principal TestSerialization la cuál implementa todo el código de forma concreta.

La clase Author

La clase Book
La clase Publisher
La clase TestSerialization
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using Samples;

namespace Samples{
  public class TestSerialization{
    static FileStream stream = null;
    static BinaryFormatter binaryformatter = new BinaryFormatter();
    static Book b;
    public static int Main(string[] args){
      Console.WriteLine("Enter the Author ");
      Console.Write("Name: ");
      string na = Console.ReadLine();
      Console.Write("Last Name: ");
      string la = Console.ReadLine();
      Console.Write("Organization: ");
      string or = Console.ReadLine();
      Console.Write("Country: ");
      string ac = Console.ReadLine();
      Console.WriteLine("Enter the book");
      Console.Write("Title: ");
      string bt = Console.ReadLine();
      Console.Write("Publication's date: ");
      string pd = Console.ReadLine();
      Console.Write("Number of pages: ");
      string np = Console.ReadLine();
      Console.WriteLine("Enter the publisher");
      Console.Write("Name: ");
      string pn = Console.ReadLine();
      Console.Write("Country: ");
      string pc = Console.ReadLine();
      b = new Book{
 Title = bt,
 Numpages = Convert.ToInt32(np),
 PublicationDate = Convert.ToDateTime(pd),
 Author = new Author{
   Name = na,
   LastName = la,
   Organization = or,
   Country = ac
 },
 Publisher = new Publisher{
   Name = pn,
   Country = pc
 }
      };
      try{
 Console.WriteLine("Serializing ...");
 using(stream = new FileStream("Book.bin",FileMode.OpenOrCreate,FileAccess.Write)){
   binaryformatter.Serialize(stream,b);
 }
 Console.WriteLine("Done.");
 Console.WriteLine("Deserializing ...");
 using(stream = new FileStream("Book.bin",FileMode.Open,FileAccess.Read)){
   b = (Book)binaryformatter.Deserialize(stream);
   Console.WriteLine("======== Get the Author ========");
   Console.WriteLine("Name [{0}]",b.Author.Name);
   Console.WriteLine("Last Name [{0}]",b.Author.LastName);
   Console.WriteLine("Organization [{0}]",b.Author.Organization);
   Console.WriteLine("Country [{0}]",b.Author.Country);
   Console.WriteLine("======== Get the Book ========");
   Console.WriteLine("Title [{0}]",b.Title);
   Console.WriteLine("Numpages [{0}]",b.Numpages);
   Console.WriteLine("Publication's Date [{0}]",b.PublicationDate);
   Console.WriteLine("======== Get the Publisher ========");
   Console.WriteLine("Name [{0}]",b.Publisher.Name);
   Console.WriteLine("Country [{0}]",b.Publisher.Country);
 }
      }catch(SerializationException ex){
 Console.WriteLine(ex.Message);
      }
      return 0;
    }
  }
}

Este ejemplo básicamente crea un grafo de una relación de clases y lo serializa (lo pasa de la memoria hacia un medio de almacenamiento) en un archivo binario e inmediatamente lo deserializa, (del medio de almacenamiento lo trae a la memoria).En todo este proceso (excepto en donde se indique que no) se convierte el objeto Book,sus clases relacionadas y sus miembros en un flujo de bytes hacia el disco duro para posteriormente recuperarlo con el mismo proceso en orden inverso. Todo esto se logra en esencia con las siguientes líneas.Para serializar y deserializar respectivamente:

using(stream = new FileStream("Book.bin",FileMode.OpenOrCreate,FileAccess.Write)){
   binaryformatter.Serialize(stream,b);
 }
using(stream = new FileStream("Book.bin",FileMode.Open,FileAccess.Read)){
   b = (Book)binaryformatter.Deserialize(stream);
}
Al compilar y ejecutar el programa, mediante los siguientes comandos:
$ mcs /t:library Author.cs Book.cs Publisher.cs /out:Samples.dll
$ mcs -r:Samples.dll TestSerialization.cs
$ mono TestSerialization.cs


Mostramos la serialización y deserialización de un grafo de objetos relacionados.

domingo, 29 de abril de 2012

Habilitando contraseñas en Switches y Routers

Una de las recomendaciones minímas de seguridad para switches y routers es la de habilitar un password para el acceso a la consola, al Privileged EXEC mode (modo privilegiado de comandos) y a las terminales virtuales o VTY's. Aunque mostramos los comandos para un switch, estos comandos sirven igualmente para un router.

Para asegurar el Privileged EXEC mode con un password, se ejecutan los siguientes comandos (se muestran en forma abreviada):

SW1> en
SW1# config t
SW1(config)# enable secret [the Password]
SW1(config)# exit
SW1# disable
Siempre se recomienda usar enable secret en lugar de enable password, porque el password se guarda de forma encriptada en la configuración.
Para quitar el password del Privileged EXEC mode se ejecutan los siguientes comandos:
SW1> en
Password: [Teclear the Password]
SW1# config t
SW1(config)# no enable secret 
SW1(config)# exit
SW1# disable

Para asegurar con un password la consola se ejecutan los siguientes comandos:

SW1> en
SW1# config t
SW1(config)# line con 0
SW1(config-line)# password [thePassword]
SW1(config-line)# login
SW1(config-line)# exit
SW1(config)# exit
SW1# disable
Para quitar el password de la consola se ejecutan los siguientes comandos:
User Access Verification

Password: [Teclear the Password]

SW1> en
SW1# config t
SW1(config)# line con 0
SW1(config-line)# no login
SW1(config-line)# exit
SW1(config)# exit
SW1# disable

Para asegurar las terminales virtuales con un password se ejecutan los siguientes comandos:

SW1>en
SW1# conf t
SW1(config)# line vty 0 15
SW1(config-line)# password [thePassword]
SW1(config-line)# login
SW1(config-line)# exit
Para quitar el password de las terminales virtuales se ejecutan los siguientes comandos:
SW1>en
SW1# conf t
SW1(config)# line vty 0 15
SW1(config-line)# no login
SW1(config-line)# exit

Es importante tener unas buenas políticas de contraseñas, por ejemplo no usar el mismo password para todos los switches o routers, ni tampoco usar password fáciles de adivinar como: cisco, Cisco123, router, etc.

sábado, 31 de marzo de 2012

Entendiendo la clase Process de .NET

La definición clásica de proceso [1] nos dice que un proceso "es un programa en ejecución" también nos señala que un proceso es más que un programa, ya que por programa se refiere únicamente al conjunto de instrucciones que se van ejecutando dentro del proceso, por lo que subraya que un proceso es una entidad activa que tiene un contador de programa (program counter), un conjunto de recursos asociados y ese conjunto de instrucciones que están representadas por el programa.
Un proceso tiene los siguientes estados durante su ejecución:

  1. Nuevo (New): El proceso se ha creado
  2. En ejecución (Running): Las instrucciones están siendo ejecutadas.
  3. En espera (Waiting): El proceso esta en espera de algún evento ocurra.
  4. Listo (Ready): El proceso esta en espera de una asignación del procesador.
  5. Terminado (Terminated): El proceso ha terminado su ejecución.

.NET proporciona la clase Process que representa un proceso del sistema operativo con todas sus propiedades y operaciones, esta clase se encuentra dentro del ensamblado System.Diagnostics.
A continuación mostramos el listado correspondiente a un proyecto GTK# de MonoDevelop, este programa sencillo muestra el uso de esta clase.


Primeramente obtenemos el nombre del host del cuál obtendremos sus procesos en ejecucción, este nombre lo asignamos a una variable de tipo string para después mostrarlo en una etiqueta de la interfaz gráfica


lbMachineName.Text = machineName = System.Environment.MachineName;

Teniendo el nombre del host, entonces con el metódo estático GetProcesses de la clase Process obtenemos un arreglo de procesos representados mediante la clase Process, este arreglo sera nuestro model (Model) para mostrar en el control GTK# TreeView de la interfaz gráfica, a continuación el código con el cuál realizamos esta función:

var resp = (from p in Process.GetProcesses(machineName)
where p.Id > 100
orderby p.ProcessName ascending select p);
Process[] arrProcesses = resp.ToArray();

Por útimo obtemos la información detallada del proceso, con el metódo estático GetProcessById un metódo que recibe como argumento un entero representando el pid (process identifier), esto se realiza con el código siguiente:


TreePath[] selected_paths = trProcessList.Selection.GetSelectedRows ();
TreeIter iter;
int pid;
foreach (TreePath p in selected_paths)
{
if (store.GetIter (out iter, p)) {
pid = Convert.ToInt32(store.GetValue(iter,1));
Process process = Process.GetProcessById(pid);
lbVirtualMemory.Text = Convert.ToString(process.WorkingSet64 / 1024) + " Kb";
lbPriority.Text = process.PriorityClass.ToString();
lbStartProcessorTime.Text = process.StartTime.ToString("HH:mm:ss.ffff");
}
}
Las siguientes imagenes muestran el programa en ejecucción



[1]Basado en el libro “Operating System Concepts”, Silberschatz Abraham, Baer Galvin Peter, Greg Gagne; John Wiley & Sons inc, 7 edición, 2005, Chapter 3

lunes, 19 de marzo de 2012

Flujos de entrada y salida en .NET

Todos los programas de computadora hacen uso de dispositivos de entrada y salida, los más clásicos para estos fines son el teclado (entrada estándar) y la consola salida (salida estándar).
.NET hace una abstracción de cada uno de estos dispositivos con el modelo de flujos (bajo el (concepto) de flujo), haciendo la analogía como si se tratase de una corriente de agua, solo que para el caso de las aplicaciones .NET se trata de corrientes de bytes. En resumen la comunicación entre .NET y el hardware de la computadora se realiza mediante el concepto de flujos.
La clase base para el tratamiento de estos flujos es la clase Stream, de la cuál derivan los flujos necesarios para la comunicación de los programas hacia el respaldo (persistencia) o en términos de .NET el Backing Store. .NET a diferencia de Java utiliza la misma clase para los flujos de entrada como para los de salida. A continuación la lista de los flujos básicos de entrada/salida:



  • FileStream: hacia archivos de disco

  • MemoryStream: hacia estructuras de memoria

  • NetworkStream: hacia conexiones de red


A continuación, mostramos como ejemplo un proyecto GTK# realizado en MonoDevelop cuyo diseño de pantalla se muestra en la siguiente imagen:


Ahora se muestra el listado que utiliza algunos de estos conceptos para leer un archivo binario .mp3 y obtener la información correspondiente al los datos del ID3 tag en estos archivos.


Primeramente en el código utilizamos las clases FileStream, BinaryReader, FileInfo del ensamblado System.IO, el cuál utilizamos en el encabezado:


using System.IO;

Con las siguientes lineas utilizamos la clase FileInfo para obtener algunas propiedades acerca del archivo, propiedades que mostramos en las etiquetas de la interfaz.

file = new FileInfo(fc.Filename);
int size = Convert.ToInt32(file.Length);
lbFileName.Text = file.Name;
lbWriteTime.Text = file.LastWriteTime.ToString();
lbFileSize.Text = size.ToString();

Ahora con el siguiente código implementamos toda la funcionalidad para la lectura de un archivo binario, utilizando un FileStream hacia un archivo creando un flujo de bytes como entrada que dirigimos hacia un BinaryReader (Lector binario) con el cuál utilizando el metódo ReadBytes para leer un arreglo de 128 bytes que son los bytes que contienen los datos del ID3 tag.

FileStream fis = new FileStream(file.FullName,FileMode.Open,
FileAccess.Read,FileShare.Read);
using(BinaryReader reader = new BinaryReader(fis))
{
int offset = size - 128;
reader.BaseStream.Position = offset;
b = reader.ReadBytes(128);
}

Una vez obtenido el arreglo de bytes,lo convertimos a caracteres, para que utilicemos la longitud y la posición correcta de cada dato según el estándar ID3, esto se logra con el siguiente código:

char[] c = new char[128];
for(int i = 0;i < b.Length;i++)
c[i] = (char)b[i];
string strTag = new string(c,0,3);
if(strTag.Equals("TAG")){
PutMsg("File loaded");
txtTitle.Text = new string(c,3,30);
txtArtist.Text = new string(c,33,30);
txtAlbum.Text = new string(c,63,30);
txtYear.Text = new string(c,93,4);
txtComments.Buffer.Text = new string(c,97,30);
}

Una vez compilada la aplicación, al ejecutarse utilizaremos el botón "open" para seleccionar un archivo mp3 del sistema de archivos.


Una vez que el archivo ha sido cargado se mostrará la información correspondiente:



martes, 28 de febrero de 2012

Sobrecarga de operadores en C# utilizando vectores

Además de los operadores para los tipos primitivos, C# tiene una característica conocida como sobrecarga de operadores la cuál permite que los operadores para tipos primitivos puedan utilizarse con objetos, permitiéndonos definir el tipo de operación, como se va a efectuar, los tipos involucrados y valor que devuelve, un ejemplo típico de esta funcionalidad lo tenemos en la concatenación de objetos String en donde se utiliza el símbolo "+" para la concatenación de cadenas que igualmente es utilizado para la adicción de enteros, como se muestra en los siguientes ejemplos:


Adicción de enteros
--------------------
int a = 18;
int b = 66;
Console.Write(a + b); //imprime 84

Concatenación de cadenas
-------------------------

String s1 = "Once upon ";
String s2 = "a hero ";
Console.Write(s1 + s2); //imprime Once upon a hero

Para ejemplificar como funciona la sobrecarga de operadores en objetos utilizaremos las operaciones con vectores que se estudian en el álgebra lineal, por lo que antes de codificar daremos algunas definiciones.

Un vector es un objeto perteneciente a un espacio vectorial, que para los casos particulares de espacios R2 y R3 podemos representarlos gráficamente como segmentos de línea dirigidos con un punto inicial y un punto final describiendo la asociación de una magnitud y una dirección.

Un espacio vectorial consiste de:

  1. Un campo F de escalares (en general los número reales).
  2. Un conjunto V de elementos llamados vectores.
  3. Un conjunto de reglas (u operaciones) llamadas suma y multiplicación que según los textos especialistas en la materia se dividen en dos categorías, una para la adicción y otra para la multiplicación.

Los axiomas para la adición espacios vectoriales son:
  • A1. Si u y v están en V, entonces u + v está dentro de V
  • A2. u + v = v + u para todos u y v que estan en V
  • A3. u + (v + w) = (u + v) + w para todos los u,v y w en V
  • A4. Un elemento 0 en V existe tal que v + 0 = v para cada v en V.
  • A5. Para cada v en V, existe un elemento -v en V tal que -v + v = 0 y v + (-v) = 0


Los axiomas para la multiplicación son:
  • S1. Si v esta en V entonces av esta en V para cada a en R.
  • S2. a(v + w) = av + aw para cada v y w en V y para cada a en R.
  • S3. (a+b)v = av + bv para cada v en V y para cada a y b en R.
  • S4. a(bv) = (ab)v para cada v en V y para todos cada a y b en R.
  • S5. 1v = v para cada v en V.

Ahora con estos conceptos pasemos al código, primeramente crearemos nuestra clase Vector en donde utilizando la palabra reservada operator definiremos las operaciones para demostrar algunos de los axiomas expuestos. A continuación el listado de dicha clase.


Como vemos en este código utilizamos la sobrecarga de operadores utilizando la palabra clave operator en los siguientes métodos:


public static Vector operator +(Vector u,Vector v)
public static Vector operator *(Vector u, Vector v)
public static Vector operator -(Vector u)
public static Vector operator *(double d,Vector v)
public static Vector operator *(Vector v,double d)

Aquí definimos la operación, el número de parámetros con los que se llevará a cabo y por supuesto su implementación.
Ahora con el siguiente listado mostraremos la utilización de clase Vector y el uso de la sobrecarga de operadores para vectores de números reales:

Si agregamos estas clases a un proyecto de consola en MonoDevelop podemos tener una solución lista para corregir y compilar.

Al ejecutar la solución, veremos el resultado como en la siguiente imagen:

martes, 21 de febrero de 2012

El Plan de pruebas

De las diferentes etapas del ciclo de desarrollo de sistemas, la etapa de pruebas es una de las que más recursos técnicos, administrativos y humanos puede necesitar, incluso hay ocasiones en donde dicha etapa supera o iguala el tiempo requerido para el resto de las etapas previas, por poner como ejemplo utilizando el tiempo como variable, supongamos que para el desarrollo de un sistema necesitamos x meses para las etapas de análisis, diseño y construcción entonces dependiendo del negocio y la criticidad de dicho sistema podemos requerir 2x de tiempo para las pruebas, lo cuál agrega costos adicionales al proyecto que afectan el presupuesto, sobretodo si no se esta seguro de que el sistema funcionará y se tiene una fecha compromiso.


Uno de los documentos iniciales de la fase de pruebas es el documento denominado Plan de pruebas el cuál y de forma general nos indica la estrategia de pruebas, los tipos, los roles y los criterios tanto de entrada como de salida de dichas pruebas.


A continuación como ejemplo, describo lo que dicho documento debe contener (pongo entre corchetes los párrafos que deben cambiar o complementarse ya que únicamente estan a manera de guía) lo siguiente:


Plan de pruebas



1-. Introducción

[Este plan de Pruebas o Programa de Pruebas describe la forma estándar de realizar las actividades de pruebas necesarias para cumplir con los controles de calidad y la verificación del funcionamiento del sistema XXX en cada uno de sus módulos y del sistema de manera global.]

1.1 Propósito

[Describe la estrategia de pruebas utilizada para el sistema XXX para establecer como se diseñan, ejecutan y se administran las pruebas, así también los tipos de pruebas y los recursos necesarios para su ejecución. Esto se realiza con el objetivo de identificar defectos y fallas, evaluar la calidad y determinar el cumplimiento de los requerimientos.]

1.2 Alcance

[Para esta versión del Sistema xxx se aplicarán los siguientes tipos de pruebas, las cuales se desarrollan conforme a los requisitos funcionales y a los controles de calidad.]

1.2.1 Pruebas funcionales

[Las pruebas funcionales deben focalizarse en cualquier requerimiento para probar que puedan ser rastreados directamente a los casos de uso, o reglas de negocio. Su objetivo es verificar la correcta aceptación, procesamiento y recuperación de los datos; así como la implementación apropiada de las reglas de negocio.]

1.2.2 Pruebas de Interfaz de usuario

[Estas pruebas verifican la interacción del usuario con el sistema. Su objetivo es asegurar que la interfaz gráfica de usuario (GUI) proporcione al usuario un acceso adecuado y una navegación a través de las pantallas del sistema.]

1.2.3 Pruebas de control de acceso

[Estas pruebas garantizan que, basado en la seguridad deseada, los actores estén restringidos a funciones/ casos de uso específicos o estén limitados a los datos que estén disponibles para ellos de acuerdo a su rol.]

2.1 Ambientes de prueba

[A continuación se listan los requerimientos mínimos de Hardware y Software.]

2.1.1 Hardware

[Listar todo el hardware necesario para el ambiente de pruebas, por ejemplo:
a) Estaciones de trabajo con y de RAM
b) Impresoras
c) Terminales con x,y ó z características.]

2.1.2 Software

[Listar todo el software necesario para el ambiente de pruebas, por ejemplo:
a) Sistemas Operativos x,y ó z
b) Navegadores x,y ó z a partir de la versión x
c) Suite de oficina versión x]

2.2.1 Roles y responsabilidades

[Aquí describir la participación de cada uno de los roles que participarán en la actividad de pruebas]

3 Actividades de prueba

3.1 Estrategia de pruebas

[La estrategia de pruebas se concentra en probar extensivamente el sistema para encontrar el mayor número de hallazgos inconsistencias, errores o excepciones en el sistema como parte de la ejecución de los casos de prueba.]

3.1.1 Procesos y actividades

3.1.1.1 Ciclo 1 Pruebas Unitarias

[Describir paso a paso cada una de las actividades de las pruebas unitarias]

3.1.1.2 Ciclo 2 Pruebas Funcionales

[Describir paso a paso cada una de las actividades de las pruebas funcionales]

3.1.1.3 Ciclo 3 Pruebas integrales

[Describir paso a paso cada una de las actividades de las pruebas integrales]

3.1.2.1 Pruebas Generales

[Documentar el conjunto de condiciones o variables bajo las cuáles el analista de pruebas determinará si el sistema xxx cumple con los requisitos solicitados.
Los requisitos generales que el sistema debe cumplir para su aprobación corresponden con: (aquí se sigue con la lista del tipos de pruebas que se efectuarán) ]

3.1.2.1.1 Interfaz de usuario

[a) Verificar la correspondencia entre el documento de diseño de interfaz aprobado y la implementación ejecutable del sistema.
b) Alineación de los elementos (márgenes).
c) Homogenización de estilos.
d) Corrección de ortografía.
e) Consistencia con diferentes cambios de resolución.
f) Correspondencia pantalla-fase en el Mapa de navegación.
g) Proporcionar mensajes apropiados para el manejo de errores.
h) Proporcionar (si aplica) mensajes con una retroalimentación y guías efectivos.
i) Consistencia en los elementos gráficos.
j) Organización y distribución apropiada de los elementos en la pantalla.
k) Verificar que los iconos sean significativos.]

3.1.2.1.2 Validación de las entradas

[a) Permitir solamente enteros o decimales en las entradas numéricas.
b) No permitir la entrada de caracteres especiales en las entradas para cadenas.
c) Validar los campos obligatorios.
d) Validar los límites mínimos o máximos de los campos.
e) Permitir únicamente fechas en las entradas de fechas.]

3.1.2.1.3 Funcionalidad

[a) Verificar que cada botón en la pantalla realice la funcionalidad para la que fue diseñada.
b) Que corresponda el componente con todos los requisitos solicitados por el usuario.
c) Que el sistema corresponda con los escenarios de funcionalidad esperados por el usuario.
d) Verificar el cumplimiento de la navegación entre componentes (pantallas, subprocesos, reportes).]

3.1.2.2 Documentación base para la ejecución de las pruebas

[Aquí va toda la documentación necesaria para esta etapa que se genero en las etapas anteriores.]

3.1.3 Criterios.

3.1.3.1 Criterios de Entrada

[Para comenzar la fase de pruebas del sistema, se deben de cumplir los siguientes criterios:
a) Construcción finalizada de cada componente
b) Ambiente de pruebas
c) Generación de los datos de prueba.]

3.1.3.2 Criterios de terminación

[a) Cuando no se encuentren hallazgos que impidan la operación del sistema. (ciclo 1)
b) Para los ciclos 2 y 3 se deberá contar con la aceptación del usuario.
c) El usuario deberá ser capaz de borrar los registros que haya creado.
d) Una vez que el usuario haya firmado de conformidad la funcionalidad del sistema. El área de desarrollo de sistemas no hará cambio alguno a la aplicación sin la previa solicitud correspondiente.]

4 Resultados

[Aquí se colocan todos los artefactos (documentos o reportes conteniendo el resultado de cada uno de los casos de prueba.]



El Plan de pruebas puede variar dependiendo de la metodología que se esté utilizando, pero a groso modo este es un ejemplo de como está estructurado este documento inicial e importante para la etapa de pruebas.

lunes, 30 de enero de 2012

Subnetting en redes IPV4 parte II, IPv4 de los números de hosts

Para sacar los números de host en una red con subneteo utilizamos los bits del último octeto, aquellos que no hayan sido utilizados para la subnet, por lo tanto estos bits serán utilizados para el número total de hosts.


Por ejemplo de la subred 130.3.12.128 necesitamos encontrar la IP número 20 o bien la vigésima IP de esa subred, bien la configuración de los octetos para esta subred se encuentran de la siguiente forma:



Bien en el último octeto entonces buscaremos el número 20 de acuerdo con los valores en decimal de los bits. Por lo que la configuración en el último octeto quedaría con los siguientes bits encendidos de acuerdo a su representación numérica.


Se realiza la suma decimal de los tres bits encendidos en el último octeto, dos de ellos representando el número de IP más el bit encendido del campo de subred.

128 + 16 + 4 = 148

Por lo que la vigésima IP de la subred 130.3.12.128 sería entonces la

130.3.12.148

Veamos ahora un segundo ejemplo, buscamos la última IP de host en la subred 400 de la red 130.3.0.0/25, por lo que la configuración de los octetos de esta subred queda de la siguiente forma:


Sumando la representación decimal de los bits encendidos del tercer octeto tenemos entonces:

128 + 64 + 8 = 200

Por lo que la IP para subred 400 es: 130.3.200.0.

Ahora vamos a utilizar el último octeto para obtener la última IP de esta subred, sabemos bien que la configuración para todos los hosts de esta subred es poniendo todos los bits encendidos excepto el del último octeto el cual representaría la IP del Gateway.
Por lo que la configuración del último host de esta subred en el último octeto queda de la siguiente forma:


Sumando su representación decimal

64 + 32 + 16 + 8 + 4 + 2 = 126

Por lo que la IP para el último host de la subred 400 es: 130.3.200.126