05 marzo 2010

La librería Synapse (1)

Buscando componentes de comunicaciones alternativos a los indocumentados Indy, me encontré con esta librería que soporta diversos protocolos TCP/IP sin tener que instalar ningún componente en Delphi. Además es gratuita y viene con todo el código fuente abierto.

La última versión es la release nº 39 con fecha 9/10/2009 y se encuentra en esta página web:

http://www.synapse.ararat.cz/doku.php

Nos vamos al apartado Download y nos bajamos la última versión estable:

Donde tengamos el directorio de los otros componentes, creamos la carpeta Synapse y descomprimimos dentro este zip:

Luego solo tenemos que preocuparnos de enlazar la carpeta \Synapse\source\lib dentro del Search Path de nuestro proyecto.

Vamos a ver todo lo que se puede hacer con esta librería. Para hacer las pruebas he utilizado Delphi 2007.

CREAR UN CLIENTE TFTP

El protocolo TFTP (Trivial File Transfer Protocol – Protocolo de Transferencia de Archivos Trivial) es una versión descafeinada del protocolo FTP que solo permite subir o bajar archivos directamente del servidor sin tener en cuenta usuarios, carpetas, permisos, etc.

Para realizar el transporte de datos utiliza el protocolo UDP usando el puerto 69 (en vez del 21 como el FTP). Como necesitaba un servidor TFTP para hacer las pruebas, me bajé el servidor gratuito tftpd32:

Se puede descargar de esta página web:

http://tftpd32.jounin.net/

Solo hay que ejecutarlo y listo. Por defecto, comparte los archivos que están en su misma carpeta, pero podemos pulsar el botón Browse para cambiarla. Comencemos a crear el servidor con un nuevo proyecto te tenga este formulario:

Debemos añadir la unidad FTPTSend en la sección uses de la unidad actual. Y como dije antes, enlazamos la carpeta \Synapse\source\lib dentro del Search Path de nuestro proyecto.

El formulario se divide en tres partes principales:

1º La dirección del servidor y el puerto que va a utilizar el usuario:

Los componentes TEdit que he utilizado se llaman Servidor y Puerto.

2º El apartado para descargar un archivo del servidor:

El componente TEdit donde metemos el nombre del archivo se llama Descargar. Al pulsar el botón BDescargar hacemos lo siguiente:

procedure TFClienteTFTP.BDescargarClick(Sender: TObject);
var
Cliente: TTFTPSend;
begin
// Creamos el cliente
Cliente := TTFTPSend.Create;

// Establecemos los parámetros de conexión
Cliente.TargetHost := Servidor.Text;
Cliente.TargetPort := Puerto.Text;

// ¿Podemos descargar el archivo?
if Cliente.RecvFile(Descargar.Text) then
begin
// Lo guardamos a disco
Cliente.Data.SaveToFile(ExtractFilePath(Application.ExeName) + Descargar.Text);
EMensajeDescarga.Caption := 'OK';
EMensajeDescarga.Font.Color := clGreen;
end
else
begin
EMensajeDescarga.Caption := 'ERROR: ' + Cliente.ErrorString;
EMensajeDescarga.Font.Color := clMaroon;
end;

EMensajeDescarga.Visible := True;

// Liberamos el cliente
Cliente.Free;
end;

He utilizado la etiqueta EMensajeDescarga que por defecto está invisible para mostrar OK o Error en caso de que falle. No hace falta introducir la ruta del archivo en el servidor, sólo el nombre del mismo:

3º Y otro apartado para subir un archivo al servidor:

El usuario debe pulsar el botón Examinar para volcar el nombre con la ruta al campo TEdit llamado Subir:

procedure TFClienteTFTP.BExaminarClick(Sender: TObject);
begin
if AbrirArchivo.Execute then
Subir.Text := AbrirArchivo.FileName;
end;

AbrirArchivo es un componente TOpenDialog. Al pulsar el botón BSubir comprobamos antes si el archivo es válido:

procedure TFClienteTFTP.BSubirClick(Sender: TObject);
var
Cliente: TTFTPSend;
begin
// Comprobamos si el usuario ha seleccionado el archivo
if Subir.Text = '' then
begin
Application.MessageBox('Seleccione el archivo que desea subir al servidor.',
'Atención', MB_ICONEXCLAMATION);
ActiveControl := Subir;
Exit;
end;

// Comprobamos si el archivo a subir existe
if not FileExists(Subir.Text) then
begin
Application.MessageBox('El archivo que intenta subir al servidor no existe.',
'Atención', MB_ICONEXCLAMATION);
ActiveControl := Subir;
Exit;
end;

// Creamos el cliente TFTP
Cliente := TTFTPSend.Create;

// Establecemos los parámetros de conexión
Cliente.TargetHost := Servidor.Text;
Cliente.TargetPort := Puerto.Text;

// Intentamos subir el archivo
Cliente.Data.LoadFromFile(Subir.Text);

if Cliente.SendFile(ExtractFileName(Subir.Text)) then
begin
EMensajeSubida.Caption := 'OK';
EMensajeSubida.Font.Color := clGreen;
end
else
begin
EMensajeSubida.Caption := 'ERROR: ' + Cliente.ErrorString;
EMensajeSubida.Font.Color := clMaroon;
end;

EMensajeSubida.Visible := True;

// Liberamos el cliente
Cliente.Free;
end;

Como puede verse en ambos casos, el código a escribir para la transferencia de archivos por TFTP entre el cliente y el servidor es extremadamente sencilla. Solo le he encontrado un inconveniente y es que no tiene ningún evento especial para monitorizar la transferencia en tiempo real, algo imprescindible para poner una barra de progreso.

CREAR UN SERVIDOR TFTP

Ahora le damos la vuelta a la tortilla y vamos a implementar el servidor para sustituir tftp32. Aquí la cosa no va tan fácil ya que hay que crear todo el servidor a mano leyendo y procesando los mensajes del mismo. Como es natural, me he basado en las demos que lleva esta librería para crearlo, pasando a español todo lo que he podido de la clase que controla el servidor.

Para empezar creamos un nuevo proyecto con este formulario:


Volvemos a vincular la carpeta \Synapse\source\lib dentro del Search Path de nuestro proyecto y añadimos la unidad FTPTSend.

Le he metido el campo Directorio de la clase TEdit para guardar el directorio por defecto que comparte los archivos. También tiene un componente TMemo llamado Mensajes para monitorizar el estado del servidor.

Por si queremos cambiar el directorio que comparte con los clientes, podemos pulsar el botón BExaminar para elegir otro directorio:

procedure TFServidorTFTP.BExaminarClick(Sender: TObject);
var
sDirectorio: string;
begin
if SelectDirectory('Seleccione un directorio', '', sDirectorio) then
Directorio.Text := sDirectorio;
end;

Ahora vamos a crear el servidor. Para que la aplicación no se quede bloqueada hay que meter el servidor dentro de un hilo de ejecución que procese las peticiones de los clientes. Lo primero es crear la clase que controla al servidor:

type
// Hilo encargado de recibir mensajes de los clientes
THiloServidor = class(TThread)
private
{ Private declarations }
FServidor: TTFTPSend;
FIP: string;
FPuerto: string;
FMensaje: string;
procedure ActualizarMensajes;
protected
procedure Execute; override;
public
constructor Create(sIP, sPuerto: string);
end;

El constructor solo recoge la IP y el puerto:

constructor THiloServidor.Create(sIP, sPuerto: string);
begin
FIP := sIP;
FPuerto := sPuerto;
inherited Create(False);
end;

También va a tener un procedimiento sincronizado para enviar al formulario los mensajes, ya que un hilo no puede manejar componentes VCL directamente:

procedure THiloServidor.ActualizarMensajes;
begin
FServidorTFTP.Mensajes.Lines.Add(FMensaje);
end;

Y ahora viene la parte gorda, la encargada de recibir mensajes de los clientes y enviar o recibir archivos a los mismos:

procedure THiloServidor.Execute;
var
RequestType: Word;
FileName: String;
begin
// Creamos el servidor encargado de escuchar a los clientes
FServidor := TTFTPSend.Create;
FMensaje := 'Servidor arrancado con el puerto ' + FPuerto + '.';
Synchronize(Actualizarmensajes);
FServidor.TargetHost := FIP;
FServidor.TargetPort := FPuerto;

try
// Mientras no termine el hilo de ejecución escuchamos los
// mensajes de los clientes
while not Terminated do
begin
// ¿Ha llegado algún mensaje?
if FServidor.WaitForRequest(RequestType,FileName) then
begin
// Mostramos quién realiza las solicitudes
case RequestType of
1:FMensaje := 'Solicitan lectura de ' +
FServidor.RequestIP + ':' + FServidor.RequestPort;

2:FMensaje := 'Solicitan escritura de ' +
FServidor.RequestIP + ':' + FServidor.RequestPort;
end;

Synchronize(ActualizarMensajes);
FMensaje := 'Archivo: ' + Filename;
Synchronize(ActualizarMensajes);

// Procesa la solicitud
case RequestType of
1:begin // Solucitud de lectura (RRQ)
if FileExists(FServidorTFTP.Directorio.Text + FileName) then
begin
FServidor.Data.LoadFromFile(FServidorTFTP.Directorio.Text +
FileName);

if FServidor.ReplySend then
begin
FMensaje := '"' + FServidorTFTP.Directorio.Text +
FileName + '" correctamente enviado.';
Synchronize(ActualizarMensajes);
end;
end
else
FServidor.ReplyError(1, 'Archivo no encontrado');
end;

2:begin // Solicitud de escritura (WRQ)
if not FileExists(FServidorTFTP.Directorio.Text + FileName) then
begin
if FServidor.ReplyRecv then
begin
FServidor.Data.SaveToFile(FServidorTFTP.Directorio.Text +
FileName);
FMensaje := 'Archivo guardardo en ' +
FServidorTFTP.Directorio.Text + FileName;
Synchronize(ActualizarMensajes);
end;
end
else
FServidor.ReplyError(6, 'El archivo ya existe.');
end;
end;
end;
end;
finally
FServidor.Free;
end;
end;

Por último, al crear el formulario establecemos como ruta de compartición de archivos el mismo directorio del programa y arrancamos el servidor:

procedure TFServidorTFTP.FormCreate(Sender: TObject);
begin
Directorio.Text := ExtractFilePath(Application.ExeName);
HiloServidor := THiloServidor.Create('0.0.0.0', '69');
end;

Ahora ejecutamos el servidor y el cliente, y probamos a enviar y recibir archivos:

Utilizando en nuestro software los clientes y servidores de TFTP podemos hacer una transferencia de información entre programas en una red local, independientemente de la conexión al servidor de bases de datos. La velocidad es muy rápida y fiable, pero como he dicho antes, hecho de menos controlar el progreso de la descarga cuando los archivos son grandes.

Quizás la librería Synapse no sea tan sofisticada como los componentes Indy, pero por lo menos dan ejemplos y documentación bastante asequible. En el próximo artículo seguiré investigando sobre otros protocolos.

Pruebas realizadas en RAD Studio 2007.

26 febrero 2010

El experto GExperts (y 3)

Finalizamos en esta serie de tres entradas dedicadas a GExperts viendo otras opciones como los buscadores de archivos, las dependencias o la sustitución automática de componentes.

GREP RESULTS

Esta opción muestra la ventana de resultados de una búsqueda de Grep, un excelente buscador de archivos que destaca por permitir buscar trozos de texto dentro los archivos de código fuente:


Supongamos que estoy buscando donde está definida la clase TIdSocketHandle dentro de los componentes KelvinIndy que me he instalado. Entonces pulso el botón de la lupa y escribo esto:

Abajo en el campo Directories elegimos la carpeta por donde queremos que se inicie la búsqueda y pulsamos el botón Ok. Volverá a la ventana de resultados de Grep con todas las unidades donde ha encontrado dicha cadena:

Si hacemos clic sobre cualquier unidad de la lista se desplegarán todas las líneas que ha encontrado de dicha unidad, incluyendo el número de línea y las coincidencias:

Si además pulsamos sobre una de las líneas nos mostrará la zona donde está en la parte inferior de la ventana:

En esta misma ventana tenemos también las opciones de reemplazar el texto buscado o imprimirlo. Lo que más sorprende de Grep es la velocidad a la que busca, es sorprendente. Aunque si lo que estáis buscando son solo archivos (sin mirar el contenido) el buscador más rápido es Everything (gratuito).

GREP SEARCH

Es la misma ventana de búsqueda que hemos visto antes:

Es para ir directamente a buscar sin pasar por la ventana de resultados.

HIDE/SHOW NON-VISUAL

Si tenemos que organizar un formulario donde hay una pasada de componentes no visuales encima del mismo:

Podemos seleccionar esta opción para hacer invisibles los componentes no visuales hasta que recoloquemos los componentes visuales:


IDE MENU SHORTCUTS

Esta es otra gran idea añadida a este experto que permite asignar una combinación de teclas a cualquier opción del menú de Delphi en esta ventana:

Por ejemplo, la opción File -> Open no tiene ninguna combinación de teclas asignada, así que la selecciono en esta ventana:

Para asignarle una combinación antes hay que activar la opción Apply a custom shortcut to this menu item y asigno por ejemplo la combinación CTRL + O. Podemos comprobar si ha ido bien la asignación en el mismo Delphi:

De este modo, podemos acelerar nuestro trabajo sin coger el ratón.

MACRO LIBRARY

La librería de macros nos permite guardar una serie de acciones que efectuemos regularmente en Delphi para que se ejecuten de una sola vez:

No se si será mi versión de Delphi, pero cada vez que intento grabar una macro se queda completamente colgado incluso a veces se cierra todo el IDE de golpe. ¿Se supone que funciona esto o es mi versión de Delphi 2007?

MESSAGE DIALOG

Esta opción nos permite escribir rápidamente el código de un mensaje de error, pregunta, advertencia, etc. Por ejemplo:

Nos generará este código al pulsar el botón Ok:

MessageDlg('¿Desea eliminar este cliente?', mtConfirmation, [mbYes, mbNo], 0);

También permite crear mensajes utilizando Application.MessageBox:


OPEN FILE

Este es un buscador que permite encontrar cualquier tipo de archivo dentro del proyecto con solo ir escribiendo su nombre:

Según la pestaña que seleccionemos, permite buscar los archivos del proyecto, las librerías según la ruta de búsqueda, etc. También es muy rápido aunque no permite hacer búsquedas según el contenido (para eso tenemos Grep).

PE INFORMATION

Esta utilizad permite conocer la cabecera de cualquier archivo ejecutable. Si seleccionamos el Bloc de notas de Windows (NOTEPAD.EXE) nos dará esta información:

La pestaña Imports nos dice que librerías DLL utiliza al ejecutarse:

Al pulsar sobre cualquier DLL nos dice las funciones que tiene. Esta utilidad puede ser interesante por si queremos hacer nuestra aplicación portable y averiguar que archivos DLL deberían acompañar al ejecutable.

PROCEDURE LIST

Esta es la ventana de procedimientos que permite buscar todos los métodos de la unidad actual:

El filtro de búsqueda se activa nada más comenzar a escribir.

PROJECT DEPENDENCIES

La ventana de dependencias del proyecto nos muestra todas las unidades de nuestro proyecto:

Y seleccionando cualquiera de ellas podemos ver a su derecha las unidades que usa:

Incluso las dependencias externas (Indirect Dependencies):


PROJECT OPTIONS SET

En esta ventana podemos activar o desactivar todas las directivas del proyecto de una sola tajada:

También se puede declarar en la pestaña Sets la variables de entorno para que luego compilemos con condicionantes.

RENAME COMPONENTS

Con esta ventana podemos renombrar o mejor dicho, asignar un prefijo a los componentes de un formulario según su clase. Por ejemplo, si quiero que todas las etiquetas tengan el prefijo E, hago lo siguiente:

Después de pulsar Ok, cada vez que insertemos una etiqueta en un formulario se llamará E1, E2, etc., en vez de Label1, Label2, …


REPLACE COMPONENTS

Esta potente opción nos permite cambiar los componentes de una clase por otra. Supongamos que tengo un formulario con tres botones de la clase TButton:

Ahora vamos reemplazar los botones TButton por los de la clase TBitBtn:

Lo hará automáticamente y respetando los nombres anteriores:


Esto nos permitirá sustituir unos componentes por otros sin tener que hacerlo manualmente.

SET TAB ORDER

Todos sabemos la pereza que da el tener que ordenar la tabulación de los componentes de un formulario, pero con esta ventana lo podemos organizar todo:

Podemos cambiar el orden manteniendo pinchando el botón izquierdo del ratón para hacer subir o bajar posiciones. También tiene a la derecha el campo Order by Position para que lo ordene según su posición vertical.

SOURCE EXPORT

Con esta opción podemos exportar todo el código fuente de la unidad actual o el que tengamos seleccionado, exportando a los formatos HTML o RTF:

Lo mejor de todo es que conserva casi todo el formato original de nuestro editor de código:


Si queremos retocar el formato de salida podemos pulsar el botón Configure para personalizarlo:

De modo para solucionar el problema que he tenido con el color de fondo, pulso el botón HTML Background y le pongo color negro:

Lo bueno que tiene es que además lo exporta incluyendo en el mismo HTML la hoja de estilo CSS para que ocupe menos.

TO DO LIST

Esta es una lista de tareas pendientes en la que podemos apuntar todo lo que nos queda por hacer en nuestro proyecto. Para añadir un elemento a la lista debemos escribir unos comentarios especiales en el código como estos:

{#ToDo1 Revisar la validación de los campos del cliente}


//#ToDo2 No olvides adjuntar la librería Unzip.dll


Entonces abrimos la ventana TO DO LIST y pulsamos el botón de refrescar para que actualice la lista de tareas:

Aunque vemos que las tildes se las come con patatas. La idea está bien pero creo que es un poco incómodo.

MORE…

La opción More nos lleva a otras dos opciones:

Configuration: permite configurar las distintas partes de este experto como las opciones del menú, las teclas de acceso rápido, los directorios, etc.:

About: con esto podemos averiguar que versión de GExperts tenemos instalada:


CONCLUSIONES

Después de todo lo visto, debo recomendar encarecidamente este experto no solo por la calidad de sus herramientas sino también por el poco consumo de recursos que necesita y lo bien que se integra con Delphi. Con esto doy por finalizado el tema de los expertos hasta que encuentre algún otro interesante.

Pruebas realizadas en RAD Studio 2007.

19 febrero 2010

El experto GExperts (2)

Al principio parece que GExperts no es tan grande como otros expertos, pero conforme vamos ahondando en sus opciones vemos que es muy completo y con unas combinaciones de teclas bien pensadas.

COMPONENT GRID

Esta opción solo esta activa cuando estamos visualizando un formulario y lo que hace es abrir una nueva ventana que nos muestra en una rejilla el nombre de todos los componentes del formulario:

La misión de esta ventana es asignar la propiedad Tag o HelpContext a un grupo de componentes que tengan el mismo contenedor (Parent) como los GroupBox.

COMPONENTS TO CODE

Al seleccionar esta opción, extrae el código fuente de la definición de los componentes seleccionados en el formulario y los copia al portapapeles. Esto nos lo comunica antes en este mensaje:

Después solo hay que pegarlo en un bloc de notas:

Es como si extrajésemos la información directamente del archivo DFM.

COPY COMPONENTS NAME

Esta opción es parecida a la anterior, pero sólo copia al portapapeles los nombres de los componentes seleccionados:


EDITOR EXPERTS

Esta opción despliega otra serie de opciones para el editor de código:


Veamos cada opción:

Align Lines. Si tenemos este bloque de código:

Lo seleccionamos y seleccionamos GExperts -> Editor Experts -> Align Lines y mostrará los símbolos de lo que considera una igualación:

Y entonces creará esta alineación:

Change case. Con esta opción pasamos el texto seleccionado a mayúsculas, minúsculas o capitalizamos:

Comment code. Coge el código seleccionado y le pone comentarios a una línea:

Uncomment code. Al revés de la opción anterior, quita los comentarios.

Sort Selected Lines. Ordena alfabéticamente las líneas seleccionadas. Esto viene bien para organizar nuestras variables desordenadas:

Para dejarlas más accesibles:

Insert Date/Time. Inserta la fecha donde tengamos posicionado el cursor:

Locate Matching Delimiter. Al situarnos dentro de un paréntesis:

Si pulsamos sobre esta opción, seleccionará todo el ámbito del paréntesis actual:

Move to Matching Delimiter. Manda el cursor al paréntesis de cierre más próximo:

Previous Identifier Reference. Si estamos situados encima de un identificador, ya sea variable, método o clase, al pulsar sobre esta opción o la combinación de teclas CTRL + ALT + ARRIBA saltará hacia arriba si hay otra aparición del mismo, es decir, una búsqueda hacia atrás de la palabra donde estamos situados.

Next Identifier Referente. Igual que el anterior pero salta al siguiente identificador (CTRL + ALT + ABAJO).

Reverse Statement. En un bloque de código donde existan asignaciones:

Lo que hace es invertirlas (hay que seleccionar el fragmento de código primero):

Esto nos ahorra el copy-paste una barbaridad.

Select Identifier. Selecciona el identificador donde estamos situados (coge la palabra completa):

Uses Clause Manager. Abre esta ventana para añadir o quitar unidades a la claúsula uses de las secciones de interfaz e implementación:

En la parte izquierda de la ventana están las que ya tenemos incluidas y utilizamos las de la parte derecha para añadirlas a nuestra unidad mediante los botones Add to Interface y Add to Implementation.

Expand Macro Template. Abre la ventana de las macros de código predefinidas:

La forma de utilizarlas es la siguiente. Por ejemplo, escribimos en el código:

Y seleccionamos GExperts -> Editor Experts -> Expand Macro Template o bien pulsamos la combinación de teclas SHIFT + ALT + T y expandirá la macro:

Si volvemos a abrir la pantalla de las macros y pulsamos el botón Configuration veremos como están implementadas cada una de ellas:

De todos los expertos que he visto, he de reconocer que son las más sencillas de entender.

EXPERT MANAGER

Si queremos desactivar este experto, en esta ventana lo podemos deshabilitar:

Podemos seleccionar Expert -> Disable o Enable y si queremos quitarlo del todo pulsamos el botón Remove Expert.

FAVORITE FILES

Podemos añadir en esta ventana de favoritos todos los archivos que queramos:

Primero creamos nuestra estructura de carpetas para clasificar los temas y luego vamos añadiendo referencias a los archivos (sean de código o no) que solemos consultar más a menudo.

FIND COMPONENT REFERENCE

Esta opción esta muy bien pensada cuando estamos escribiendo código y queremos visualizar el componente cuyo nombre hemos seleccionado en el código:

Al seleccionar esta opción o pulsar la combinación de teclas SHIFT + CONTROL + F mostrará el formulario y seleccionará el componente:

Es ideal para encontrar un componente enterrado entre pestañas y paneles.

CONTINUARÁ…

En el próximo artículo finalizaré todas las opciones que quedan de GExperts. Todavía quedan muchas y muy interesantes.

Pruebas realizadas en RAD Studio 2007.

Publicidad