Tips para ser un buen usuario final (de computadoras)

enero 21, 2012

En la actualidad muchas personas tienen contacto con computadoras, ya sea en su trabajo o en su propia casa, pero muchas de estas personas no saben usarlas; el problema es que ellos creen que si.

El saber prender y apagar una PC, hacer un documento de texto, hoja de cálculo, usar un navegador web para buscar algo en internet o enviar un correo electrónico en mi opinión no puede describirse como “saber usar una computadora”.

A continuación pongo una lista de cosas que creo que debería tomar en cuenta todo aquel que desee ser un buen usuario final (algunos puntos parecerán obvios y algunos probablemente hasta cómicos, pero creanme, es absolutamente necesario enunciarlos, si estudió sistemas, informática, etc. y ha tratado con usuarios finales sabe de lo que hablo):

1. Saber leer y escribir

2. Si ya sabe leer, no tenga miedo de usar esa habilidad (la mayoría de los usuarios finales no leen los manuales, ni siquiera los mensajes que aparecen en pantalla cuando están usando alguna aplicación)

3. Por increíble que parezca, el saber leer y escribir no es suficiente para usar una computadora adecuadamente, es necesario comprender lo que se está leyendo

4. Saber la diferencia entre hardware y software

5. Conocer el hardaware de la computadora que usamos (saber que es un monitor, un mouse, un teclado, un puerto USB, un puerto paralelo, etc.)

6. Conocer la diferencia entre memoria y disco duro. En muchas ocasiones cuando he preguntado a algún usuario final ¿cuánta memoria tiene su PC? he escuchado frases como “tiene 500 gigas de memoria”. Uno pensaría “caray, no tiene una PC, tiene todo un cluster“, en realidad, el usuario se estaba refiriendo a la capacidad de almacenamiento del disco duro de su PC y no a la memoria RAM.

7. Saber qué sistema operativo se está usando (si es Ud. usuario final, probablemente le sorprenda saber que existen otros sistemas operativos además de Windows, pero afortunadamente así es) y de preferencia también saber la versión (si es Windows por ejemplo, ayuda saber qué versión de Windows, 3.0, 3.1, 3.11, 95, 95OSR, 98, 98SE, ME, 2000, XP, Vista, 7, etc.). También en innumerables ocasiones cuando he preguntado a un usuario final ¿qué sistema operativo tiene instalado su PC? he recibido como respuesta ¿en dónde veo eso?.

8. Conocer la diferencia entre sistema operativo y cualquier otra aplicación, como por ejemplo una suite de oficina (típicamente una suite de oficina incluye un procesador de palabras, un ahoja de cálculo y un software para presentaciones)

9. Saber usar la aplicación que el sistema operativo de nuestra PC tiene instalada para el manejo de archivos. Esto incluye saber copiar archivos o moverlos de un lugar a otro, renombrar archivos, eliminar archivos, etc.

10. Saber descomprimir un archivo (por lo menos si está en formato zip).Esto incluye saber qué significa que un archivo esté comprimido y la diferencia entre “ver” lo que contiene un archivo comprimido y “descomprimirlo”

11. Saber usar un navegador web

12. Saber la diferencia entre una página web y una dirección de correo electrónico

13. Saber a que se refiere alguien  cuando nos pregunta ¿qué tipo de archivo es? ó ¿cuál es la ruta del archivo?

14 Entender lo que significa “formatear el disco duro”, “resetear o reiniciar la PC”, “respaldar la información”

15 Recordar la ubicación en donde guardamos nuestros archivos (ya sea que los descarguemos de internet o que los creemos con alguna aplicación)

16. Tener claro que las computadoras “no piensan” (tampoco adivinan lo que deseamos hacer). Más de una vez he visto que cuando el apuntador del mouse cambia de forma para indicar que se está realizando algún proceso (en Windows toma la forma de un reloj de arena) el usuario final dice que la computadora “está pensando”. Creanme, cuando eso pase (que las computadoras piensen), si habrá que preocuparnos

Sería bueno que los usuarios finales supieran todavía algunas otras cosas más, pero los usuarios finales que sepan por lo menos estos 16 puntos, tendrán una mejor experiencia al usar una computadora, le sacarán mayor provecho a su computadora y será más fácil para la persona de sistemas a la que pidan ayuda cuando la necesiten, el poder ayudarles.

Gráfica de barras horizontales en la terminal con C++

diciembre 14, 2011

Ya en un post anterior había escrito sobre la STL de C++; el código siguiente simula una gráfica de barras horizontales en modo texto y aprovecho para ejemplificar el uso de algunas funciones y algoritmos de la STL.
El programa consiste en pedirle al usuario que capture números positivos y los va almacenando en un vector, para terminar la captura el usuario debe introducir un número negativo. Una vez terminada la captura, se copian los valores almacenados en el vector a otro vector y después se ordenan para que en el vector original los números queden en el mismo orden en que el usuario los fue capturando. Esta parte de copiar los valores de un vector a otro y ordenar los valores en el segundo vector no es necesaria para el funcionamiento del programa, sólo lo pongo para ejemplificar com se haría esto usando la STL.

En el programa utilizo funciones de la STL para encontrar el valor menor y el valor mayor en el vector original sin tener que ordenarlo.

Aquí está el código
Archivo grafica_barrash.cpp

#include <iostream>
#include <vector>
#include <algorithm>
#include <math.h>

using namespace std;

int main()
{
 int i_x=0, i_y=0;
 double dbl_valor=0, dbl_escala=0;
 vector<double> v_valores, v_ordenados;
 vector<double>::iterator v_valores_it, v_ordenados_it;
 vector<double>::const_iterator menor_it, mayor_it, valor_it;

 cout << "Teclee un número, (cualquier número negativo para terminar):" << endl;
 /* Mientras el usuario teclee números positivos (incluido el cero), guardamos en el vector
    v_valores los números que el usuario va tecleando
 */
 while (dbl_valor >= 0)
       {
        cin >> dbl_valor;
        if (dbl_valor >= 0)
            v_valores.push_back(dbl_valor);
       }

 cout << endl << "Estos son los números que Ud. introdujo:" << endl;
 // Muestra los valores almacenados en el vector v_valores
 for ( v_valores_it = v_valores.begin(); v_valores_it != v_valores.end(); v_valores_it++)
      cout << *v_valores_it << endl;

 // Hace el vector v_ordenados del mismo tamaño que el vector v_valores
 v_ordenados.resize (v_valores.size());
 // Copia los valores del vector v_valores al vector v_ordenados
 copy (v_valores.begin(), v_valores.end(), v_ordenados.begin());
 // Ordena el vector v_ordenados
 std::sort(v_ordenados.begin(), v_ordenados.end());

 cout << endl << "Estos son los números ordenados:" << endl;
 // Muestra los valores almacenados en el vector v_ordenados
 for ( v_ordenados_it = v_ordenados.begin(); v_ordenados_it != v_ordenados.end(); v_ordenados_it++)
      cout << *v_ordenados_it << endl;

 menor_it = min_element(v_valores.begin(), v_valores.end());
 mayor_it = max_element(v_valores.begin(), v_valores.end());

 cout << endl << "El valor menor es: " << *menor_it << endl;
 cout << "El valor mayor es: " << *mayor_it << endl;

 // Obtiene la escala
 dbl_escala = *mayor_it - *menor_it;
 cout << "La escala es: " << dbl_escala << endl << endl;

 for (i_x=0; i_x<8; i_x++)
      cout << " ";

 cout << ceil(*menor_it);
 for (i_x=0; i_x<=34; i_x++)
      cout << " ";
 cout << ceil((dbl_escala/2)+*menor_it);
 for (i_x=0; i_x<=34; i_x++)
      cout << " ";
 cout << ceil(*mayor_it);
 cout << endl;
 for (i_x=0; i_x<8; i_x++)
      cout << " ";
 cout << "|";
 for (i_x=0; i_x<=34; i_x++)
      cout << " ";
 cout << "|";
 for (i_x=0; i_x<=34; i_x++)
      cout << " ";
 cout << "|" << endl;

 // Dibuja las barras
 i_x=1;
 for ( v_valores_it = v_valores.begin(); v_valores_it != v_valores.end(); v_valores_it++)
     {
      cout << "Valor"<< i_x;
      /* Si el valor de x es de un sólo dígito, deja 2 espacios antes de empezar a dibujar la barra, de lo contrario
         deja sólo uno
      */
      cout << (i_x < 10 ? "  " : " ");
      valor_it = v_valores_it;
      for (i_y=1; i_y<= ((double)(*valor_it - *menor_it)/dbl_escala)*72+1; i_y++)
           cout << "*";
      cout << endl;
      i_x++;
     }

 return 0;
}

Implementación de pilas con apuntadores en C

octubre 21, 2011

En este post muestro como implementar las funciones push y pop para el manejo de pilas, y dos problemas clásicos que se pide se solucionen utilizando pilas.

El siguiente archivo contiene la implementación de las funciones push y pop para ser utilizadas con caracteres

//Archivo pila_char.h
#include <stdio.h>
#include <stdlib.h>

typedef struct nodo_s
{
 char dato;
 struct nodo_s *siguiente;
} nodo_t;

typedef nodo_t *ptrNodo;
typedef nodo_t *ptrPila;

/*
    Agrega un nodo al inicio de la lista ligada
    *pila es el apuntador que apunta al primer nodo de la lista ligada (la cima de la pila)
*/
void push(ptrPila *pila, char x)
{
 // Crea un nuevo nodo
 ptrNodo nodo;
 nodo = (ptrNodo)malloc(sizeof(nodo_t));
 if (nodo != NULL)
    {
     nodo->dato = x;
     // El apuntador nodo->siguiente va a apuntar al primer nodo de la lista ligada
     nodo->siguiente = *pila;
     // pila va a apuntar al nuevo nodo, con esto hacemos que el nuevo nodo sea ahora el primer nodo de la lista ligada
     *pila=nodo;
    }
}

/*
    Elimina el primer nodo de la lista ligada
    *pila es el apuntador que apunta al primer nodo de la lista ligada (la cima de la pila)
*/
char pop(ptrPila *pila)
{
 // Crea un nuevo nodo
 ptrNodo nodo;
 char x;
 
 // El nuevo nodo va a apuntar al primer nodo de la lista ligada
 nodo = *pila;
 x = (*pila)->dato;
 // Ahora el segundo nodo de la lista ligada va a ser el primero
 *pila = (*pila)->siguiente;
 // Borra el primer nodo de la lista ligada
 free(nodo);
 // Regresa el valor que contenía el nodo que se eliminó
 return x;
}

/*
    Regresa 1 si no hay nodos en la lista ligada y cero en caso contrario
    *pila es el apuntador que apunta al primer nodo de la lista ligada (la cima de la pila)
*/
int pila_vacia(ptrPila *pila)
{
 return (*pila == NULL ? 1:0);
}

/*
   Muestra los datos de los nodos
*/ 
void nodos_pila(ptrNodo nodo)
{
 if (nodo == NULL)
     printf("La pila está vacia\n");
 else
     {
      while (nodo != NULL)
            {
             printf("%c\n",nodo->dato);
             nodo = nodo->siguiente;
            }
      printf("\n");
     }
}

El siguiente es un programa de ejemplo que permite analizar una cadena y determinar si los paréntesis o corchetes están balanceados, las funciones están hechas de tal forma que podemos agregar también llaves, etc. ya que sólo hay que indicar cuál es el caracter que abre y cuál es el caracter que cierra.

// Archivo pila_parentesis.c

#include <stdio.h>
#include "pila_char.h"

int verifica_balance(char expresion[], char cabre, char ccierra);

int main()
{
 char cadena[]="2*[x+q(3s-2)]/[((x+1)*x+(s-2))]";
 int i=0;
 
 // Muestra la cadena
 printf("La cadena a analizar es la siguiente:\n\n");
 while (cadena[i] != '\0')
       {
        printf("%c", cadena[i]);
        i++;
       }
 
 printf("\n\n");
 // Verifica si los paréntesis están balanceados
 if (verifica_balance(cadena, '(', ')') == 1)
     printf("Los paréntesis están balanceados\n");
 else
     printf("Los paréntesis NO están balanceados\n");
 
 // Verifica si los corchetes están balanceados
 if (verifica_balance(cadena, '[', ']') == 1)
     printf("Los corchetes están balanceados\n");
 else
     printf("Los corchetes NO están balanceados\n");
 
 return 0;
}

int verifica_balance(char expresion[], char cabre, char ccierra)
{
 int x=0, balanceados=1;
 ptrPila pila = NULL;
 
 // Recorre la cadena
 while (expresion[x] != '\0' && balanceados == 1)
       {
        // Si el elemento coincide con el caracter que abre, lo ingresa en la pila
        if (expresion[x]==cabre)
            push(&pila, expresion[x]);
        else
            // Si el elemento coincide con el caracter que cierra, lo saca de la pila
            if (expresion[x]==ccierra)
               {
                /* Si la pila está vacía, significa que los caracteres no están balanceados
                   porque se encontró un caracter que cierra sin que exista antes un caracter que abre
                */
                if (pila_vacia(&pila) != 1)
                    pop(&pila);
                else
                    balanceados = 0;
               }
        x++;
       }
 
 /* Si balanceados = 1 pero la pila no está vacía, los caracteres no están balanceados
    porque quedaron caracteres que abren sin tener su caracter que cierra
 */ 
 if (balanceados == 1 && pila_vacia(&pila) != 1)
     balanceados = 0;

 // Se asegura de dejar la pila vacia
 while (pila_vacia(&pila) != 1)
        pop(&pila);
 
 return balanceados; 
}

El siguiente archivo contiene la implementación de las funciones push y pop para ser utilizadas con enteros

// Archivo pila_int.h

#include <stdio.h>
#include <stdlib.h>

typedef struct nodo_s
{
 int dato;
 struct nodo_s *siguiente;
} nodo_t;

typedef nodo_t *ptrNodo;
typedef nodo_t *ptrPila;

/*
    Agrega un nodo al inicio de la lista ligada
    *pila es el apuntador que apunta al primer nodo de la lista ligada (la cima de la pila)
*/
void push(ptrPila *pila, int x)
{
 // Crea un nuevo nodo
 ptrNodo nodo;
 nodo = (ptrNodo)malloc(sizeof(nodo_t));
 if (nodo != NULL)
    {
     nodo->dato = x;
     // El apuntador nodo->siguiente va a apuntar al primer nodo de la lista ligada
     nodo->siguiente = *pila;
     // pila va a apuntar al nuevo nodo, con esto hacemos que el nuevo nodo sea ahora el primer nodo de la lista ligada
     *pila=nodo;
    }
}

/*
    Elimina el primer nodo de la lista ligada
    *pila es el apuntador que apunta al primer nodo de la lista ligada (la cima de la pila)
*/
int pop(ptrPila *pila)
{
 // Crea un nuevo nodo
 ptrNodo nodo;
 int x=0;
 
 // El nuevo nodo va a apuntar al primer nodo de la lista ligada
 nodo = *pila;
 x = (*pila)->dato;
 // Ahora el segundo nodo de la lista ligada va a ser el primero
 *pila = (*pila)->siguiente;
 // Borra el primer nodo de la lista ligada
 free(nodo);
 // Regresa el valor que contenía el nodo que se eliminó
 return x;
}

/*
    Regresa 1 si no hay nodos en la lista ligada y cero en caso contrario
    *pila es el apuntador que apunta al primer nodo de la lista ligada (la cima de la pila)
*/
int pila_vacia(ptrPila *pila)
{
 return (*pila == NULL ? 1:0);
}

void nodos_pila(ptrNodo nodo)
{
 if (nodo == NULL)
     printf("La pila está vacia\n");
 else
     {
      while (nodo != NULL)
            {
             printf("%d\n",nodo->dato);
             nodo = nodo->siguiente;
            }
      printf("\n");
     }
}

Como ejemplo, el clásico programa para hacer operaciones aritméticas en notación postfix

// Archivo pila_postfixexpr.c

#include <stdio.h>
#include "pila_int.h"

int main()
{
 char cadena[]="45+72-*5/";
 int i=0, num1=0, num2=0, result=0;
 ptrPila pila = NULL;
 
 // Muestra la cadena
 printf("La cadena a analizar es la siguiente:\n\n");
 while (cadena[i] != '\0')
       {
        printf("%c", cadena[i]);		
        i++;
       }
 
 i=0;
 printf("\n\n");
 // Recorre la cadena
 while (cadena[i] != '\0')
       {
        // Si el elemento no es un operador, lo ingresa en la pila
        if (cadena[i]!='+' && cadena[i]!='-' && cadena[i]!='*' && cadena[i]!='/')		   
            push(&pila, ((int)cadena[i])-48);   // El código ASCII de 0 es 48
        else
             {
              num2=pop(&pila);
              num1=pop(&pila);
              switch (cadena[i])
                     {
                      case '+':
                               result = num1+num2;
                               printf("suma %d + %d = %d\n",num1, num2, result);
                               push(&pila, result);
                               break;
                      case '-':
                               result = num1-num2;
                               printf("resta %d - %d = %d\n",num1, num2, result);
                               push(&pila, result);
                               break;
                      case '*':
                               result = num1*num2;
                               printf("multiplica %d * %d = %d\n",num1, num2, result);
                               push(&pila, result);
                               break;
                      case '/':
                               result = num1/num2;
                               printf("divide %d / %d = %d\n",num1, num2, result);
                               push(&pila, result);
                               break;
                     }			 
              }
        i++;
       }

 if (pila_vacia(&pila)!=1)
    {
     printf("\n\nLos elementos en la pila son los siguientes;\n\n");
     // Muestra los elementos que están en la pila
     nodos_pila(pila);
    }
 
 return 0;
}

Instalar Sinatra + PostgreSQL + Datamapper en Debian Squeeze

septiembre 28, 2011

Sinatra es un DSL para desarrollo web utilizando el lenguaje de programación Ruby. A diferencia de Rails, Sinatra NO obliga a seguir el patrón Modelo Vista Controlador (aunque es posible desarrollar aplicaciones web de ese tipo con Sinatra). He notado que la mayoría de las personas que desarrollan aplicaciones web con acceso a base de datos, utilizan MySQL o incluso SQLite, pero yo prefiero PostgreSQL y no hay razón por la que no se pueda utilizar con Sinatra, así que en este post voy a utilizar ambos junto con un ORM llamado Datamapper para crear los modelos y erb para crear las vistas.

Instalar Ruby

Debian Squeeze trae la versión 1.8.7 de Ruby y la versión 1.9.2, vamos a instalar la versión más reciente (note que el paquete debian se llama ruby1.9.1 pero trae la versión 1.9.2 de Ruby)

sudo apt-get install ruby1.9.1

Una vez instalado, creamos un enlace simbólico al que llamaremos simplemente ruby

cd /usr/bin
sudo ln -s ruby1.9.1 ruby

Instalar RubyGems

De la página http://rubygems.org/pages/download descargamos el archivo .zip o .tgz y lo descomprimimos. Si se descarga el archivo rubygems-1.8.10.tgz, al descomprimirlo se crea un directorio rubygems-1.8.10, hay que cambiarse a ese directorio y ejecutar

sudo ruby setup.rb

Ahora creamos un enlace simbólico al que llamaremos gem

cd /usr/bin
sudo ln -s gem1.9.1 gem

Instalar Sinatra

sudo gem install sinatra

Ya tenemos instalado Sinatra, para probarlo, haremos un programa en Ruby con el clásico hola mundo :). El archivo lo guardamos con el nombre holamundo.rb


# holamundo.rb
require 'sinatra'

get '/' do
'Hola Mundo!'
end

Ahora desde la terminal tecleamos

ruby holamundo.rb

Y aparece lo siguiente:

== Sinatra/1.2.6 has taken the stage on 4567 for development with backup from WEBrick
[2011-09-26 13:39:22] INFO  WEBrick 1.3.1
[2011-09-26 13:39:22] INFO  ruby 1.9.2 (2010-08-18) [i486-linux]
[2011-09-26 13:39:22] INFO  WEBrick::HTTPServer#start: pid=3076 port=4567

Abrimos un navegador web y nos vamos a

http://localhost:4567

y veremos el texto Hola Mundo!

Para parar la ejecución, vamos a la terminal y tecleamos Ctrl-C y aparece

== Sinatra has ended his set (crowd applauds)
[2011-09-26 13:40:50] INFO  going to shutdown …
[2011-09-26 13:40:50] INFO  WEBrick::HTTPServer#start done.

Si en lugar del servidor web WEBrick queremos utilizar Thin, debemos instalar los paquetes ruby1.9.1-dev y build-essential

sudo apt-get install ruby1.9.1-dev build-essential

y ahora si instalamos Thin

sudo gem install thin

Instalar PostgreSQL

sudo apt-get install postgresql postgresql-contrib libpq-dev

Debemos poner un password al usuario postgres

sudo passwd postgres

Nos cambiamos al usuario postgres y asignamos un password al usuario postgres dentro de PostgreSQL

su postgres
psql -c “ALTER USER postgres WITH PASSWORD ‘password_aqui’” -d template1

Aparece ALTER ROLE y nos muestra nuevamente el prompt

Todavia como el usuario postgres crear un nuevo usuario en PostgreSQL. Para crear el usuario en PostgreSQL vamos a indicar que sea superusuario (-s), que PostgreSQL nos pida indicar el password para dicho usuario (-P) y nos muestre en pantalla los mensajes que esto genere (-e de –echo)

En este caso el usuario que voy a crear se llamará sysdba y le pondré como password la palabra s3cret

createuser -P -s -e sysdba

Aparece lo siguiente:

Ingrese la contraseña para el nuevo rol:
Ingrésela nuevamente:
CREATE ROLE sysdba PASSWORD ‘md51767410185836193fcba975fe021e85b’ SUPERUSER CREATEDB CREATEROLE INHERIT LOGIN;

Salimos del usuario postgres con exit

Editamos el archivo /etc/postgresql/8.4/main/pg_hba.conf para indicar que el usuario que acabamos de crear puede accesar a la linea de comandos de PostgreSQL (psql)

sudo nano /etc/postgresql/8.4/main/pg_hba.conf

Agregamos la linea
local   all         sysdba                           md5

en la sección # Database administrative login by UNIX sockets

y queda algo parecido a esto

# Database administrative login by UNIX sockets
local   all         postgres                          ident
local   all         sysdba                            md5

Reiniciamos el servidor PostgreSQL

sudo /etc/init.d/postgresql restart

Aparece

Restarting PostgreSQL 8.4 database server: main.

Nos conectamos a la línea de comandos de PostgreSQL con el usuario que creamos (en este caso sysdba) y creamos una base de datos para pruebas

psql -U sysdba template1

Aparece:

psql (8.4.8)
Digite «help» para obtener ayuda.

template1=#

Tecleamos \l para ver la lista de las bases de datos que existen actualmente

template1=# \l
Listado de base de datos
Nombre   |  Dueño   | Codificación | Collation  |   Ctype    |      Privilegios
———–+———-+————–+————+————+———————–
postgres  | postgres | UTF8         | es_MX.utf8 | es_MX.utf8 |
template0 | postgres | UTF8         | es_MX.utf8 | es_MX.utf8 | =c/postgres
: postgres=CTc/postgres
template1 | postgres | UTF8         | es_MX.utf8 | es_MX.utf8 | =c/postgres
: postgres=CTc/postgres
(3 filas)

template1=#

Crearemos una nueva base de datos (en este caso se llamará development)

template1=# CREATE DATABASE development;
CREATE DATABASE
template1=#

Verificamos que se haya creado la base de datos

template1=# \l
Listado de base de datos
Nombre    |  Dueño   | Codificación | Collation  |   Ctype    |      Privilegios
————-+———-+————–+————+————+———————–
development | sysdba  | UTF8         | es_MX.utf8 | es_MX.utf8 |
postgres    | postgres | UTF8         | es_MX.utf8 | es_MX.utf8 |
template0   | postgres | UTF8         | es_MX.utf8 | es_MX.utf8 | =c/postgres
: postgres=CTc/postgres
template1   | postgres | UTF8         | es_MX.utf8 | es_MX.utf8 | =c/postgres
: postgres=CTc/postgres
(4 filas)

template1=#

Salimos de la terminal de PostgreSQL

template1=# \q

Instalar el gem para conectarse desde Ruby a PostgreSQL

sudo gem install pg

Para checar que está funcionando, entramos a la linea de comandos de ruby (desde la terminal tecleamos irb1.9.1) y tecleamos

require ‘pg’

Nos debe regresar true. Salimos con quit

$ irb1.9.1
irb(main):001:0> require ‘pg’
=> true
irb(main):002:0> quit

Instalar Datamapper

sudo gem install data_mapper

Instalar el adaptador que permite a Datamapper comunicarse con la base de datos (en este caso PostgreSQL)

sudo gem install dm-postgres-adapter

Ya tenemos instalado todo lo necesario para desarrollar aplicaciones web con acceso a base de datos utilizando Sinatra!. Para probarlo pongo a continuación un pequeño programa con las vistas y un archivo css.

Programa principal

El programa contiene un modelo en Datamapper llamado Linea, este modelo crea la tabla lineas en la base de datos development que creamos después de que instalamos PostgreSQL La tabla contiene sólo 2 campos; el campo cve_linea que es la llave primaria y el campo linea.

El programa hace las funciones de creación, lectura, actualización, borrado y listado de registros en la tabla

Archivo sinatra_test.rb


require 'sinatra'
require 'data_mapper'

configure do
# Se conecta a la base de datos
DataMapper.setup(:default, 'postgres://localhost/development')
DataMapper.setup(:default, {
  :adapter  => 'postgres',
  :host     => 'localhost',
  :username => 'sysdba' ,
  :password => 's3cret',
  :database => 'development'})
end

# Modelos
class Linea
  include DataMapper::Resource
  property :cve_linea, String, :length => 4, :required => true, :key => true
  property :linea, String, :length => 30, :required => true
end

DataMapper.auto_upgrade!

def campo_vacio(campo)
    campo.empty?
end

# menú principal
get '/' do
  erb :index
end

# muestra error debido a que un campo requerido se sejó vacío
get '/campo_vacio' do
  erb :error_campovacio
end

# *******************************
# LINEA
# *******************************

# nueva linea
get '/linea' do
  erb :reg_linea
end

# muestra el listado de lineas
get '/listalineas' do
  @lineas = Linea.all :order => :cve_linea
  erb :lista_lineas
end

# guarda la información de la linea
post '/linea' do
  @linea = Linea.new(:cve_linea => params[:cve_linea].upcase, :linea => params[:linea].upcase)
  if !campo_vacio(params[:cve_linea]) and !campo_vacio(params[:linea])
     if @linea.save
        redirect "/linea/#{@linea.cve_linea}"
     else
         redirect '/linea'
     end
  else
      redirect '/campo_vacio'
  end
end

# muestra los detalles de la linea
get '/linea/:cve_linea' do
  @linea = Linea.get(params[:cve_linea])
  if @linea
     erb :cons_linea
  else
      redirect '/linea'
  end
end

# muestra la forma para editar la linea
get '/editlinea/:cve_linea' do
  @linea = Linea.get(params[:cve_linea])
  if @linea
     erb :edit_linea
  else
      redirect '/listalineas'
  end
end

# muestra la forma para borrar la linea
get '/borralinea/:cve_linea' do
  @linea = Linea.get(params[:cve_linea])
  if @linea
     erb :borra_linea
  else
      redirect '/listalineas'
  end
end

# edita la linea
put '/editlinea/:cve_linea' do
  @linea = Linea.get(params[:cve_linea])
  if @linea
     @linea.linea = params[:linea].upcase
     @linea.save
     redirect '/listalineas'
  end
end

# borra la linea
delete '/borralinea/:cve_linea' do
  @linea = Linea.get(params[:cve_linea])
  if @linea
     @linea.destroy
     redirect '/listalineas'
  end
end

En el directorio en donde guardamos el programa principal (sinatra_test.rb) creamos dos directorios, uno llamado public y otro llamado views.
Dentro del directorio public creamos otro directorio que llamaremos stylesheets. Dentro de este directorio stylesheets vamos a poner nuestro archivo css (que llamaremos style.css). Sólo contendrá el código que nos permita “mostrar” el texto en mayúsculas automáticamente en los campos de captura. el programa sinatra_test.rb es el que convierte a mayúsculas el texto antes de guardarlo en la tabla.

Desde luego, ustedes pueden agregar el código css necesario para embellecer a su gusto la presentación de la aplicación.

Archivo public/stylesheets/style.css

.campo_entrada
{
 text-transform: uppercase;
}

Ahora en el directorio views vamos a crear las vistas

Archivo views/layout.erb

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Ejemplo Sinatra</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="Acceso a base de datos en PostgreSQL" />
<meta name="keywords" content="Sinatra, Ruby, Datamapper" />
<link href="/stylesheets/style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<%= yield %>
</body>
</html>

Archivo views/error_campovacio.erb

<div>
    <p>La información no se guardó debido a que dejó un campo vacío, por favor verifique!
    <p><a href="/">Menú Principal</a></p>
</div>

Archivo views/index.erb

<h1>Menú Principal</h1>

<p><a href="/linea">Registro de líneas</a></p>
<p><a href="/listalineas">Listado de líneas</a></p>

Archivo views/reg_linea.erb

<div>
    <form action="/linea" method="post" accept-charset="utf-8">
      <label>Clave de línea </label><input type="text" name="cve_linea" id="cve_linea" maxlength=4>
      <br/>
      <label>Línea </label><input type="text" name="linea" id="linea" maxlength=30>
      <br/>
      <input type="submit" value="Guardar"/>
    </form>
    <p><a href="/">Menú Principal</a></p>
</div>

Archivo views/cons_linea.erb

<div>
    <label>Clave de línea </label><%= @linea.cve_linea %>
    <br/>
    <label>Línea </label><%= @linea.linea %>
    <p><a href="/linea">Registro de líneas</a></p>
    <p><a href="/">Menú Principal</a></p>
</div>

Archivo views/edit_linea.erb

<div>
    <form action="/editlinea/<%= @linea.cve_linea %>" method="post" accept-charset="utf-8">
       <input type="hidden" name="_method" value="put">
       <label>Clave de línea </label><%= @linea.cve_linea %>
       <br/>
       <label>Línea </label><input type="text" name="linea" id="linea" maxlength=30 value="<%= @linea.linea %>">
       <br/>
       <input type="submit" value="Guardar"/>
    </form>
    <p><a href="/listalineas">Listado de líneas</a></p>
    <p><a href="/">Menú Principal</a></p>
</div>

Archivo views/borra_linea.erb

<div>
    <p>Se borrará la siguiente línea: </p>
    <form action="/borralinea/<%= @linea.cve_linea %>" method="post" accept-charset="utf-8">
       <input type="hidden" name="_method" value="delete">
       <label>Clave de línea </label><%= @linea.cve_linea %>
       <br>
       <label>Línea </label><%= @linea.linea %>
       <br/>
       <input type="submit" value="Borrar"/>
    </form>
    <p><a href="/listalineas">Listado de líneas</a></p>
    <p><a href="/">Menú Principal</a></p>
</div>

Archivo views/lista_lineas.erb

<p>Líneas registradas: <%= @lineas.length %></p>
<table>
<tr>
   <th>Clave de línea</th>
   <th>Línea</th>
   <th></th>
   <th></th>
</tr>
<% @lineas.each do |linea| %>
   <tr>
      <td><%= linea.cve_linea %></td>
      <td><%= linea.linea %></td>
      <td><a href="/editlinea/<%= linea.cve_linea %>">[editar]</a></td>
      <td><a href="/borralinea/<%= linea.cve_linea %>">[borrar]</a></td>
   </tr>
<% end %>
</table>
<p><a href="/">Menú Principal</a></p>

Instalar JRE en CentOS 6

agosto 9, 2011

CentOS 6 viene con Firefox 3.6.9, para instalar el plugin de Java en dicho navegador en esta versión de CentOS hay que hacer lo siguiente (básicamente son los pasos que indica la página de Java, sólo que ahi tienen algunos errores, al menos al momento en que estoy escribiendo este post):

Descargar de la página de Java el paquete (archivo RPM)

Cerrar Firefox

Desde la terminal, cambiarse al usuario root

Ir al directorio en donde se desea hacer la instalación y poner ahi el archivo RPM; en mi caso fue el archivo jre-6u26-linux-i586.rpm.bin y lo instalé en /usr/local

Agregar permisos de ejecución al archivo RPM tecleando chmod a+x jre-6u26-linux-i586.rpm.bin

Ejecutar el archivo tecleando ./jre-6u26-linux-i586.rpm.bin

Ir al directorio /usr/lib/firefox-3.6 y crear el directorio plugins

cd /usr/lib/firefox-3.6

mkdir plugins

Ir al directorio plugins y crear ahi un enlace simbólico al archivo libnpjp2.so de la instalación de Java

cd plugins

ln -s /usr/java/jre1.6.0_26/lib/i386/libnpjp2.so

Para comprobar la instalación, abrir Firefox y en la barra de direcciones teclear about:plugins (se muestran los plguins que están instalados y debe aparecer entre ellos el de Java).

Funciones básicas para listas simplemente ligadas en C

agosto 9, 2011

En este post voy a poner un archivo de cabecera que hice para poder crear programas que utilicen listas simplemente ligadas, contiene las funciones básicas y está diseñado para manejar enteros, pero es muy fácil hacer la implementación de un archivo de cabecera que acepte otro tipo de datos (char, etc.).

La estructura básica es la siguiente


typedef struct nodo_s
{
 int dato;
 struct nodo_s *siguiente;
} nodo_t;

Implementé una función para crear un nodo con el valor que contendrá el campo llamado dato, una función para insertar un nodo, para eliminar un nodo, para saber si la lista está vacía y una función que muestra todos los nodos de la lista.


// Archivo listasimple_int.h

#include <stdio.h>
#include <stdlib.h>

typedef struct nodo_s
{
 int dato;
 struct nodo_s *siguiente;
} nodo_t;

typedef nodo_t *ptrNodo;
typedef nodo_t *ptrLista;

/*
Crea un nuevo nodo y en el campo dato almacena el valor que recibe como parámetro
regresa el nodo recien creado
*/
ptrNodo crea_nodo(int valor)
{
 ptrNodo nuevo_nodo = (ptrNodo)malloc(sizeof(nodo_t));
 if (nuevo_nodo != NULL)
    {
     nuevo_nodo->dato = valor;
     nuevo_nodo->siguiente = NULL;
    }

 return nuevo_nodo;
}

/*
Agrega a la lista que recibe como parámetro, un nodo enseguida del nodo que recibe como parámetro
Si el nodo que recibe como parámetro es NULL, significa que se desea insertar el nodo al inicio de la lista
*/
void inserta_despues(ptrLista *lista, ptrNodo nodo, int valor)
{
 ptrNodo nuevo_nodo = crea_nodo(valor);

 if (nodo != NULL)
    {
     /* El apuntador nuevo_nodo->siguiente va a apuntar a la misma dirección a donde apunta
        el apuntador "siguiente" del nodo que recibe como parámetro
     */
     nuevo_nodo->siguiente = nodo->siguiente;
     /* El apuntador "siguiente" del nodo que recibe como parámetro va a apuntar al nodo recien creado
        con esto, el nodo recien creado se ha insertado adelante del nodo que se recibe como parámetro
     */
     nodo->siguiente = nuevo_nodo;
    }
 else
    {
     // Si la lista no está vacía, hace que el apuntador "siguiente" del nuevo nodo apunte al primer elemento de la lista
     if (*lista != NULL)
         nuevo_nodo->siguiente = *lista;
     // Hace que la lista apunte hacia el nuevo nodo para que sea el primer nodo de la lista
     *lista = nuevo_nodo;
    }
}

/*
  Elimina el nodo que se encuentra enseguida del nodo que recibe como parámetro
  Si el nodo que recibe como parámetro es NULL, y la lista no está vacía,
  significa que se desea borrar el primer nodo de la lista
*/
int elimina_despues(ptrLista *lista, ptrNodo nodo)
{
 int x=0;
 ptrNodo borrar_nodo = NULL;

 if (nodo != NULL)
    {
     if (nodo->siguiente != NULL)
        {
         /* El apuntador borrar_nodo va a apuntar a la misma dirección a donde apunta
            el apuntador "siguiente" del nodo que recibe como parámetro
         */
         borrar_nodo = nodo->siguiente;
         /* El apuntador "siguiente" del nodo que recibe como parámetro va a apuntar al nodo que está
            a continuación del que se va a borrar
         */
         nodo->siguiente = borrar_nodo->siguiente;
        }
    }
 else
     {
      // Si la lista no está vacia, significa que quiere borrar el primer nodo de la lista
      if (*lista != NULL)
         {
          borrar_nodo = *lista;
          *lista = borrar_nodo->siguiente;
         }
     }

 /* Si el apuntador "siguiente" del nodo que recibe como parámetro apunta a NULL, significa que el apuntador
    que se recibió como parámetro es el último de la lista, por lo tanto, no hay nodo siguiente
    Otro caso por el cual borrar_nodo puede ser null, es que la lista esté vacía, y también es imposible hacer la eliminación de un nodo
 */
 if (borrar_nodo != NULL)
    {
     x=borrar_nodo->dato;
     free(borrar_nodo);
    }
 else
     printf("Borrado prohibido\n");

 return x;
}

/*
  Regresa 1 si no hay nodos en la lista ligada y cero en caso contrario
  *lista es el apuntador que apunta a la lista ligada
*/
int lista_vacia(ptrLista *lista)
{
 return (*lista == NULL ? 1:0);
}

/*
  Muestra los datos de los nodos
*/
void nodos_lista(ptrNodo nodo)
{
 if (nodo == NULL)
     printf("La lista está vacia\n");
 else
     {
      while (nodo != NULL)
            {
             printf("%d",nodo->dato);
             nodo = nodo->siguiente;
             if (nodo != NULL)
                 printf(" -> ");
            }
      printf("\n");
     }
}

A continuación muestro un programa muy sencillo para que sirva de ejemplo de cómo utilizar este archivo de cabecera, el programa pide al usuario que vaya insertando números enteros y los va insertando en orden en una lista simplemente ligada; cuando el usuario no quiera introducir más números, debe introducir el número cero. Después, el programa da opción a borrar un número de la lista.


//      ordena_listasimple.c
//
//      Hecho por Salomón Rincón Torres <rtmex@yahoo.com>
//

#include <stdio.h>
#include "listasimple_int.h"

int main()
{
 int numero=0, insertado=0, encontrado=0;
 ptrLista lista = NULL;
 ptrNodo nodo = NULL;

do
  {
   insertado = 0;
   printf("Este programa recibe números y los va insertando en orden ascendente en una lista simplemente ligada\n");
   printf("Vaya introduciendo los números (introduzca cero para salir del programa)\n");
   scanf("%d", &numero);

   if (numero!=0)
      {
       if (lista_vacia(&lista) == 1)
           inserta_despues(&lista, NULL, numero);
       else
           {
            nodo = lista;
            if (numero <= nodo->dato)
                // Inserta el número al inicio de la lista
                inserta_despues(&lista, NULL, numero);
            else
                while (nodo != NULL && insertado == 0)
                      {
                       if (numero > nodo->dato)
                          {
                           if (nodo->siguiente != NULL)
                              {
                               if (numero > nodo->siguiente->dato)
                                   nodo = nodo->siguiente;
                               else
                                   {
                                    inserta_despues(&lista, nodo, numero);
                                    insertado = 1;
                                   }
                              } /* if */
                           else
                               {
                                inserta_despues(&lista, nodo, numero);
                                insertado = 1;
                               }
                          } /* if */
                      } /* while */
           } /* else */
       printf("\n\nLos elementos en la lista son los siguientes;\n\n");
       // Muestra los elementos que están en la lista
       nodos_lista(lista);
      } /* if */
  }
while (numero!=0);

printf("\n\nLa lista quedó con los siguientes elementos:\n\n");
// Muestra los elementos que están en la lista
nodos_lista(lista);

if (lista_vacia(&lista) != 1)
   {
    printf("\nDato a borrar\n");
    scanf("%d", &numero);

    nodo = lista;
    if (nodo != NULL)
        // Verifica si el número que se desea borrar es el primero de la lista
        if (nodo->dato == numero)
            elimina_despues(&lista, NULL);
        else
            {
             while (nodo != NULL && encontrado == 0)
                   {
                    if (nodo->siguiente != NULL)
                       {
                        if (nodo->siguiente->dato==numero)
                            encontrado = 1;
                       }
                    if (encontrado == 0)
                        nodo = nodo->siguiente;
                   }
             if (encontrado == 1)
                 elimina_despues(&lista, nodo);
            }

    printf("\n\nLa lista final quedó con los siguientes elementos:\n\n");
    // Muestra los elementos que están en la lista
    nodos_lista(lista);
   }
return 0;
}

FLISOL Puebla 2011

marzo 14, 2011

Como cada año, Puebla vuelve a participar en el Festival Latinoamericano de Instalación de Software Libre. En esta ocasión será el 9 de Abril, a continuación les dejo un banner con la información y la liga al sitio.

http://flisol.info/FLISOL2011/Mexico/Puebla

Yo estaré participando con una ponencia (Introducción al Software Libre)

Además de que pueden llevar sus equipos para que les instalen alguna distribución de GNU/Linux, les recomiendo que asistan a las conferencias, hay desde nivel básico (como la que yo voy a impartir) y nivel más avanzado, además de talleres y juegos.

Es un evento gratuito y el objetivo es dar a conocer el software libre, así que vale la pena que se den una vuelta ese día (es Sábado)

El programa completo está en la liga arriba mencionada

Instalación de Debian Squeeze en Lenovo Ideapad S12

febrero 7, 2011

Debemos descargar los archivos necesarios para hacer una memoria usb desde la cual podamos arrancar la Netbook e instalar Debian Squeeze.

Ir a http://ftp.nl.debian.org/debian/dists/squeeze/main/installer-i386/current/images/ y entrar a la opción hd-media que aparece del lado izquierdo

Descargar el archivo boot.img.gz

Ir a http://cdimage.debian.org/debian-cd/6.0.0/i386/iso-cd/ y descargar la imagen iso netinstall de Debian 6  (debian-6.0.0-i386-netinst.iso).

Insertar la memoria usb y desde la terminal teclear df -k, que en mi caso muestra la siguiente información:

Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/hda1              4806904   3638732    923988  80% /
tmpfs                   501760         0    501760   0% /lib/init/rw
udev                     10240       744      9496   8% /dev
tmpfs                   501760         0    501760   0% /dev/shm
/dev/hda3             33309260   3991576  27625640  13% /home
/dev/sda1               244476    217996     26480  90% /media/usb0

Lo que significa que la usb está en /dev/sda1.

Desmontar la memoria usb:

sudo umount /dev/sda1

Copiar el archivo boot.img.gz a la memoria usb usando el comando zcat

zcat boot.img.gz > /dev/sda1

Volver a montar la memoria usb, copiar la imagen iso y desmontar la memoria

sudo mount /dev/sda1 /media/usb0

sudo cp debian-6.0.0-i386-netinst.iso /media/usb0

sudo umount /dev/sda1

Ahora ya podemos utilizar la memoria usb para arrancar la Netbook desde ahi (hay que configurar en el BIOS de la Netbook que la usb sea el primer dispositivo de arranque)

Configuración de la tarjeta de red inalámbrica

Debian Squeeze no configura la tarjeta de red inalámbrica que viene con la Lenovo Ideapad S12, que es el modelo BCM4312 de Broadcom Corporation. Para lograr que funcione, se deben seguir los siguientes pasos (que están en http://wiki.debian.org/wl)

Agregar a nuestro archivo /etc/apt/sources.list los repositorios non-free y contrib

deb http://ftp.us.debian.org/debian/ squeeze main contrib non-free

Depués de guardar el archivo, hacer el correspondiente sudo apt-get update e instalar los paquetes module-assistant y wireless-tools

sudo apt-get install module-assistant wireless-tools

Para los siguientes pasos, les sugiero que se cambien al usuario root, ya que algunos no funcionan simplemente usando sudo.

Usando module assitant, construir e instalar el paquete broadcom-sta-modules

m-a a-i broadcom-sta

Hay que poner en la lista negra (blacklist) el módulo brcm80211 para evitar que exista conflicto con el soporte para las tarjetas de red inalámbrica BCM4313, BCM43224 y BCM43225

echo blacklist brcm80211 >> /etc/modprobe.d/broadcom-sta-common.conf

Se debe reconstruir el sistema de archivos inicial que se carga en memoria RAM cuando inicia GNU/Linux para que siempre estén bloqueados los módulos que se difinieron en /etc/modprobe.d/broadcom-sta-common.conf

update-initramfs -u -k $(uname -r)

Descargar de la memoria los módulos que causan conflicto con el módulo wl

modprobe -r b44 b43 b43legacy ssb brcm80211

Cargar el módulo wl

modprobe wl

Y con eso queda funcionando la tarjeta de red inalámbrica en Debian Squeeze en la Netbook Lenovo Ideapad S12

Configuración del cliente de mensajería en GNOME

Debian Squeeze instalado con el escritorio GNOME trae como cliente de mensajerría el paquete Empathy que por  default sólo trae la opción de usar cuentas de jabber, chat de facebook y google talk.

Para poder usar una cuenta de msn (como hotmail por ejemplo), hay que instalar el paquete telepathy-butterfly

sudo apt-get install telepathy-butterfly

Instalación del plugin de Flash

Para ver videos en Youtube, debemos tener instalado el plugin de flash, así que para instalarlo ejecutamos

sudo apt-get install flashplugin-nonfree

Instalación de LTSP 5 en Debian Lenny

octubre 28, 2010

LTSP (Linux Terminal Server Project) es un software que nos permite soportar thin clients (clientes ligeros) desde un servidor GNU/Linux.

Instalar un servidor LTSP nos permite reutilizar hardware con pocos recursos como clientes, incluso sin disco duro, ya que todos los procesos se ejecutan en el servidor.

A continuación describo las pruebas que hice con LTSP 5 y Debian Lenny.

Como servidor estoy utilizando una PC con procesador Pentium 4 a 1.8Ghz, 512MB RAM y disco duro de 20GB. Tiene instalado Debian Lenny con XFCE

La máquina más antigua que he podido hacer funcionar como thin client para este proyecto hasta el momento es una PC con procesador Pentium II a 400Mhz con 256MB RAM, sin disco duro, la tarjeta de red que tiene no soporta PXE y el Bios de la tarjeta madre no trae la opción para arrancar via red.

La configuración que yo hice es la siguiente:

El servidor tiene dos tarjetas de red (eth0 y eth1), eth0 está conectada al ruteador que da acceso a internet y eth1 esta conectada a un switch al que estan conectados los clientes. Asigné direcciones IP fijas a ambas tarjetas de red, a eth0 le asigné la dirección IP 192.168.1.73 y a eth1 la dirección IP 10.0.0.254.

Estos son los pasos que hay que hacer.

1. Instalar el paquete ltsp-server-standalone

sudo apt-get install ltsp-server-standalone

2. Editar el archivo /etc/network/interfaces para que quede de la siguiente forma (los valores para eth0 dependerán de la red en donde tengamos el router que nos proporciona la salida a internet, en esta caso la dirección IP del router es 192.168.1.254):

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
address 192.168.1.73
netmask 255.255.255.0
network 192.168.0.0
broadcast 192.168.0.255
gateway 192.168.1.254

auto eth1
iface eth1 inet static
address 10.0.0.254
netmask 255.255.255.0
network 10.0.0.0
broadcast 10.0.0.255

3. Ejecutar

sudo /etc/init.d/networking restart

4. Editar los archivos /etc/dhcp3/dhcpd.conf y /etc/ltsp/dhcpd.conf para que queden de la siguiente forma:

authoritative;

subnet 10.0.0.0 netmask 255.255.255.0 {
range 10.0.0.1 10.0.0.250;
option domain-name “ltsp.local”;
option domain-name-servers 10.0.0.254;
option broadcast-address 10.0.0.255;
option routers 10.0.0.254;
next-server 10.0.0.254;
#    get-lease-hostnames true;
option subnet-mask 255.255.255.0;
option root-path “/opt/ltsp/i386″;
if substring( option vendor-class-identifier, 0, 9 ) = “PXEClient” {
filename “/ltsp/i386/pxelinux.0″;
} else {
filename “/ltsp/i386/nbi.img”;
}
}

5. Ejecutar

sudo /etc/init.d/dhcp3-server start

Y debe aparecer el siguiente mensaje:

* Starting DHCP server dhcpd3

6. Editar el archivo /etc/default/dhcp3-server para indicarle cuál tarjeta de red utilizará el servidor DHCP (en este caso, eth1)

INTERFACES=”eth1″

7. Construir las imágenes para los clientes

sudo ltsp-build-client

Esto puede tardar un buen rato; al final aparece el siguiente mensaje:

información: la instalación del cliente LTSP se completó satisfactoriamente

8. Editar el archivo /etc/exports y agregar la siguiente linea

/opt/ltsp       *(ro,no_root_squash,async)

y ejecutar sudo invoke-rc.d nfs-kernel-server reload

9. Editar /etc/default/tftpd-hpa y cambiamos la linea RUN_DAEMON=”no” por

RUN_DAEMON=”yes”

10. Editar /etc/inetd.conf para comentar la linea de tftp para que quede asi:

#tftp           dgram   udp     wait    root  /usr/sbin/in.tftpd /usr/sbin/in.tftpd -s /var/lib/tftpboot

después reiniciar inetd ejecutando

sudo invoke-rc.d openbsd-inetd restart

también se debe reiniciar tftpd-hpa ejecutando

sudo invoke-rc.d tftpd-hpa restart

Aquellas PC que vayan a usar como clientes que tengan tarjeta de red con soporte PXE y tarjeta madre con Bios que se pueda configurar para arrancar via tarjeta de red, no necesitan hacer el paso número 11, sólo configuren la PC para que arranque desde la tarjeta de red como primera opción (esto lo hacen en el Bios)

11. Generar el floppy de arranque para los terminales que no cuentan con tarjeta de red capaz de arrancar via PXE

11.1 De la página http://rom-o-matic.net/ generar una imágen floppy bootable image (.dsk) seleccionando all-drivers en la opción “Choose a NIC type”

11.2 Después de descargada la imágen, crear un floppy a partir de ella

sudo dd if=gpxe-1.0.1-gpxe.dsk of=/dev/fd0

12. Si al arrancar el cliente, éste se cicla en la pantalla del logo, o si después de pedir el usuario y contraseña, aún introduciendo el usuario y contraseña correctos vuelve a pedir el usuario y contraseña, ejecutar en el servidor el comando

sudo /usr/sbin/ltsp-update-sshkeys

y reiniciar el cliente para volver a intentar hacer el login

 

1. Instalar el paquete ltsp-server-standalone

 

sudo apt-get install ltsp-server-standalone

 

2. Editar el archivo /etc/network/interfaces para que quede de la siguiente forma (los valores para eth0 dependerán de la red en donde tengamos el router que nos proporciona la salida a internet, en esta caso la dirección IP del router es 192.168.1.254):

 

auto lo

iface lo inet loopback

 

auto eth0

iface eth0 inet static

address 192.168.1.73

netmask 255.255.255.0

network 192.168.0.0

broadcast 192.168.0.255

gateway 192.168.1.254

 

auto eth1

iface eth1 inet static

address 10.0.0.254

netmask 255.255.255.0

network 10.0.0.0

broadcast 10.0.0.255

 

3. Ejecutar

 

sudo /etc/init.d/networking restart

 

4. Editar los archivos /etc/dhcp3/dhcpd.conf y /etc/ltsp/dhcpd.conf para que queden de la siguiente forma:

 

authoritative;

 

subnet 10.0.0.0 netmask 255.255.255.0 {

range 10.0.0.1 10.0.0.250;

option domain-name “ltsp.local”;

option domain-name-servers 10.0.0.254;

option broadcast-address 10.0.0.255;

option routers 10.0.0.254;

next-server 10.0.0.254;

# get-lease-hostnames true;

option subnet-mask 255.255.255.0;

option root-path “/opt/ltsp/i386”;

if substring( option vendor-class-identifier, 0, 9 ) = “PXEClient” {

filename “/ltsp/i386/pxelinux.0”;

} else {

filename “/ltsp/i386/nbi.img”;

}

}

 

5. Ejecutar

 

sudo /etc/init.d/dhcp3-server start

 

Y debe aparecer el siguiente mensaje:

 

* Starting DHCP server dhcpd3 [ OK ]

 

6. Editar el archivo /etc/default/dhcp3-server para indicarle cuál tarjeta de red utilizará el servidor DHCP (en este caso, eth1)

 

INTERFACES=”eth1″

 

7. Construir las imágenes para los clientes

 

sudo ltsp-build-client

 

Esto puede tardar un buen rato; al final aparece el siguiente mensaje:

 

información: la instalación del cliente LTSP se completó satisfactoriamente

 

8. Editar el archivo /etc/exports y agregar la siguiente linea

 

/opt/ltsp *(ro,no_root_squash,async)

 

y ejecutar sudo invoke-rc.d nfs-kernel-server reload

 

9. Editar /etc/default/tftpd-hpa y cambiamos la linea RUN_DAEMON=”no” por

 

RUN_DAEMON=”yes”

 

10. Editar /etc/inetd.conf para comentar la linea de tftp para que quede asi:

 

#tftp dgram udp wait root /usr/sbin/in.tftpd /usr/sbin/in.tftpd -s /var/lib/tftpboot

 

después reiniciar inetd ejecutando

sudo invoke-rc.d openbsd-inetd restart

también se debe reiniciar tftpd-hpa ejecutando

sudo invoke-rc.d tftpd-hpa restart

 

11. Generar el floppy de arranque para los terminales que no cuentan con tarjeta de red capaz de arrancar via PXE

 

11.1 De la página http://rom-o-matic.net/ generar una imágen floppy bootable image (.dsk) seleccionando all-drivers en la opción “Choose a NIC type”

 

11.2 Después de descargada la imágen, crear un floppy a partir de ella

 

sudo dd if=gpxe-1.0.1-gpxe.dsk of=/dev/fd0

 

12. Si al arrancar el cliente, éste se cicla en la pantalla del logo, o si después de pedir el usuario y contraseña, aún introduciendo el usuario y contraseña correctos vuelve a pedir el usuario y contraseña, ejecutar en el servidor el comando

 

sudo /usr/sbin/ltsp-update-sshkeys

 

y reiniciar el cliente para volver a intentar hacer el login

red inalámbrica vs red con cable

julio 28, 2010

Desde hace algún tiempo lo inalámbrico está de moda, en la mayoría de los casos cuando algún cliente necesita que se le instale una red de área local (LAN), lo primero que se le ocurre es que sea inalámbrica. Incluso varios proveedores de internet de banda ancha (ya sea compañias telefónicas o de televisión por cable) anuncian promociones en las cuales dan el “modem” inalámbrico grátis, como si fuera lo máximo.

La verdad es que es mucho mejor una red cableada que una inalámbrica, y a continuación voy a explicar las principales razones.

Velocidad

Los estándares para redes inalámbricas más utilizados son el IEEE 802.11a, 802.11b, 802.11g y 802.11n.

El estándar IEEE 802.11b es el más lento de todos los anteriores ya que permite una velocidad máxima de transmisión de 11Mbps (megabits por segundo). Funciona en la banda de 2.4Ghz.

El estándar IEEE 802.11a permite una velocidad máxima de transmisión de 54Mbps y funciona en la banda de 5Ghz. El utilizar la banda de 5Ghz en lugar de la banda de 2.4Ghz es una ventaja ya que la banda de 2.4Ghz está más saturada ya que es la misma banda que utilizan los teléfonos inalámbricos y los hornos de microondas, por lo que es más factible que haya interferencia.

El estándar IEEE 802.11g al igual que el 802.11a permite una velocidad máxima de transmisión de 54Mbps pero funciona en la banda de 2.4Ghz. Esto permite que clientes que utilizan el estándar IEEE 802.11b se puedan conectar a la red, pero la velocidad de transmisión general de la red disminuye a 22Mbps para los clientes que se conecten con el estándar 802.11g y a 11Mbps (su máximo permitido) para los clientes que se conecten con el estándar 802.11b.

El estándar IEEE 802.11n permite una velocidad máxima de transmisión de hasta 600Mbps aunque en la actualidad, ningún fabricante ha desarrollado equipos que alcancen está velocidad, la mayoría de los equipos que funcionan con este estándar alcanzan velocidades de transmisión de 300Mbps y recientemente TrendNet anunció el lanzamiento de un router que dicen alcanza hasta 450Mbps. Este estándar puede trabajar en la banda de 2.4Ghz, en la banda de 5Ghz, o en las 2 bandas al mismo tiempo.

Así que la velocidad máxima de transmisión que se tiene actualmente en una red inalámbrica es de 600Mbps (en realidad 300Mps, pero asumiendo que ya se estuvieran fabricando equipos que alcanzaran el máximo permitido por el estándar). Por otro lado, una red cableada utilizando cable UTP categoría 5e permite velocidades de transmisión de hasta 1Gigabit (1000 Mbps); es decir, casi el doble.

Seguridad

La seguridad en las redes inalámbricas siempre ha sido una de sus principales debilidades, desde el protocolo de cifrado WEP que es el más debil hastal el WPA2 que es considerado de los más seguros actualmente.

Algunas ligas que demuestran esto

http://wepcrack.sourceforge.net/
http://docs.alkaloid.net/index.php/Cracking_WEP_and_WPA_Wireless_Networks
http://sectools.org/crackers.html
http://www.youtube.com/watch?v=VVbWBoR4E64
http://www.corelan.be:8800/index.php/2009/02/24/cheatsheet-cracking-wpa2-psk-with-backtrack-4-aircrack-ng-and-john-the-ripper/

Obviamente se pueden tomar medidas adicionales como filtrar por MAC address la conexión a la red, pero si se tiene un número considerable de clientes esto no es posible.

La única forma de conectar un equipo a una red cableada es por un medio físico, es decir, conectando un cable a un puerto de un router, switch, etc. que esté conectado a la red, (sin considerar desde luego redes que tienen aceeso a internet, ya que internet es una red pública, pero este caso también aplica a las redes inalámbricas).

Estabilidad

Hay muchos factores que afectan las conexiones en una red inalámbrica:

Los materiales de construcción del lugar en donde se va a instalar la red (si son techos o paredes muy gruesas o hay muchas estructuras metálicas, etc.)

Si hay muchas redes cercanas en la misma banda, la velocidad se ve afectada porque se interfieren unas con otras

Telefonos inalámbricos, portones automáticos, hornos de microondas y cualquier dispositivo que utilize la misma banda que utiliza la red inalámbrica que se instala puede causar interferencia

En una red cableada, la mayoría de las fallas se deben a un cable o un puerto en mal estado.

Conclusión

Las redes inalámbricas tienen una sola ventaja sobre las redes con cable: “la movilidad”. Si realmente no requiere de estarse conectando a la red en cualquier lugar de su casa u oficina, no vale la pena instalar una red inalámbrica. Y note que dije “no requiere”, que es diferente a “no le gustaría”, es decir, es muy cómodo poder conetarnos a la red desde cualquier ubicación del edificio en cualquier momento, pero si no es indispensable, no se lo recomiendo.

Hay casos en los que a pesar de las ventajas de una red cableada, el requerimiento que se tiene se soluciona mejor con una red inalámbrica. Por ejemplo, supongamos que quiere instalar cámaras IP en medio de un área grande, descubierta y sin paredes cercanas, por ejemplo el estacionamiento de un campus en una universidad, en donde sólo existen los postes de las luminarias cada ciertos metros de separación entre ellos. Una opción sería pasar el cable de red de forma subterranea, pero muy probablmente sería mas costoso y llevaría más tiempo que hacer una instalación inalámbrica.

Entónces ¿cómo decidir?

La recomendación es:

“Si nada le impide cablear, instale una red cableada y no una inalámbrica”. Aunque puede tener una red hibrida, en dónde sólo haya una área en donde exista conexión inalámbrica, si no es absolutamente necesario la conexión sin cables, entónces instale sólo su red por cable.

¿Cuándo instalar una red inalámbrica en lugar de una red cableada?

A continuación menciono 3 ejemplos, pero puede haber más:

Hay ocasiones en donde no permiten hacer el cableado, ya sea porque son edificios muy viejos considerados monumentos o porque los dueños insisten en que no se vea el cable, o la canaleta, ducto, etc. por donde se va a pasar el cable y no hay ni techo ni piso falso para poder pasar el cable de forma oculta.

Casos como el del estacionamiento no techado de un campus universitario descrito anteriormente, en donde por costo y tiempo es más conveniente la solución inalámbrica

Se pretende conectar dos edificios separados y no se puede pasar cable de uno a otro


Seguir

Get every new post delivered to your Inbox.