<-- Capítulo

Índice del tutor de Delphi
© Copyright 1999
por David Martínez.

Todos los derechos reservados

Capítulo -->

Capitulo 10.2 Programando Sockets en Delphi

Ahora crearemos un pequeño sistema de comunicación por sockets en Delphi. Haremos un Cliente y un servidor.

La técnica de programación en sockets como cliente es distinta a la técnica que se utiliza como servidor. Un servidor abre un puerto para "escuchar", y sólo comienza a interpretar datos cuando un cliente se conecta. Por otro lado, un cliente abre la conexión y comienza a comunicarse de inmediato.

Programando el Cliente

Comenzaremos con el cliente. Seleccione "File-New-Application" y a continuación ponga los siguientes componentes:

Su interfaz de usuario tendrá la siguiente apariencia (o algo parecido):

Ahora debemos decidir el puerto para comunicarnos. En una situación donde vamos a comunicarnos con un servicio en otra computadora, utilizaríamos el puerto en el cual el servicio ejecuta (ej. 80 para web, 23 para Telnet, etc.). Pero como nosotros vamos a escribir un servidor además de un cliente, nos toca elegir qué puerto nos gusta más. Así que digamos que queremos el puerto 9923. Escriba "9923" en la propiedad "Port" del ClientSocket. Necesitaremos poner el mismo puerto en nuestro servidor.

Usted puede elegir cualquier puerto, pero procure utilizar puertos que no sean utilizados por servicios estándar, para reducir la posibilidad de que servicios extraños accesen nuestros servidores (aunque esta posibilidad nunca puede ser eliminada totalmente).

Ahora que ya tenemos nuestra interfaz de usuario, debemos escribir código. Comencemos por escribir algo de código para actualizar la barra de estatus: Éste es el código para los eventos OnConnect, OnDisconnect y OnError del ClientSocket (recuerde que debe hacer doble-click en estos eventos para que nos genere nuestro procedimiento):


procedure TForm1.ClientSocket1Connect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Statusbar1.Panels[0].Text := 'Conectado a ' + ClientSocket1.Host;
end;

procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Statusbar1.Panels[0].Text := 'Desconectado';
end;

procedure TForm1.ClientSocket1Error(Sender: TObject;
  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
  var ErrorCode: Integer);
begin
  mmResultados.Lines.Add('Error al conectar a ' + ClientSocket1.Host);
  ErrorCode := 0;
end;

Como verá, este código no requiere de mucha explicación. Simplemente muestra algunas cosillas en pantalla para mantener el estado actual de la conexión en pantalla. Ahora veamos cómo el Componente ClientSocket nos ahora muchísimo trabajo.

Primero necesitamos hacer que el SpeedButton nos conecte o desconecte del servidor de sockets. El código del evento OnClick en mi SpeedButton es como sigue:


procedure TForm1.sbConectarClick(Sender: TObject);
begin

  if ClientSocket1.Active then ClientSocket1.Active := False
   else begin
      ClientSocket1.Host := edtComputadora.Text;
      ClientSocket1.Active := True;
   end;

end;

Este código simplemente cambia el estado del socket, conectándolo si está desconectado y viceversa. Antes de conectar, asigna el nombre de la computadora.

Ahora tenemos un programa que puede actualizar la pantalla cuando se conecta y desconecta, así como conectarse y desconectarse. Ahora todo lo que necesitamos es código para enviar y recibir datos.

Enviar es obvio - queremos enviar cada línea que escribimos en el RichEdit. Así que simplemente utilizamos el OnKeyDown para enviar la línea cada vez que el usuario presiona [Enter]:

Recibir datos no es tan obvio, pero también es sencillo gracias a Delphi. Cada vez que nuestro Socket recibe datos, un evento "OnRead" de tipo TSocketNotifyEvent es generado. Todo lo que tenemos que hacer es escribir en el evento OnRead del ClientSocket.


procedure TForm1.reUsuarioKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin

  // Si el usuario presionó [Enter], enviamos
  // la línea anterior.
  if Key = VK_Return then
      ClientSocket1.Socket.SendText(
               reUsuario.Lines[reUsuario.Lines.Count - 1]);

end;

procedure TForm1.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
begin

  // Cada vez que el socket recibe datos,
  // un evento OnRead es generado.
  // Simplemente escribimos los datos que
  // hemos recibido en el Memo.
  mmResultados.Lines.Add(Socket.ReceiveText);

end;

Compile su programa y ejecútelo. Todavía no podrá conectarse a nada, pero si cambia el Port al número 21 y se conecta a un servidor de ftp podrá ver que su cliente recibe texto de la otra computadora. Asegúrese de cambiar el puerto de nuevo a 9923 y recompilar para que se pueda conectar al servidor.

Para verificar esto, yo modifiqué el programa ligeramente (se lo dejo de tarea) :-) para que pueda especificar el puerto al cual me voy a conectar. Después me conecte a un servidor FTP bajo Windows llamado "Calamari", me desconecté y me conecté a un servidor ftp bajo Linux llamado "Snapper".

Nuestro cliente es bastante genérico y usted puede cambiar el numero de puerto para tratar de conectarse a distintos servidores de sockets. Recuerde que se puede conectar a servidores de sockets en general, ya sean estos Windows, Linux, Solaris, Mac, etcétera. Usted incluso podría añadir otro EditBox con el número de puerto para poderlo modificar en tiempo de ejecución (se lo dejo de tarea, es muy fácil).

Programando el Servidor

Ahora que tenemos el cliente, podemos hacer un servidor que responda a las peticiones del cliente. Un servidor de sockets también es sencillo gracias a Delphi. Por ahora no nos meteremos en complejidades de hilos de ejecución, así que nuestro servidor sólo podrá mantener la conexión de un cliente a la vez (TODO: Verificar esto).

Tal como en el cliente, comience con una nueva aplicación. Nuestro servidor no necesita nada en cuanto a interfaz de usuario, pero pongamos un Memo (Nombre: mmClientes) y un StatusBar con un StatusPane de todas maneras, para que nos muestre todas las peticiones mientras las recibe.

Ahora ponga un TServerSocket en la forma. Modifique la propiedad "Port" para que utilice el puerto al cual nuestros clientes van a conectar (9923 en este ejemplo).

Su programa servidor tendrá la siguiente apariencia en modo de diseño:

Ahora debemos escribir el código de nuestro servidor. Primero queremos que en cuanto nuestro servidor arranque, que se ponga a escuchar, así que utilizaremos el OnCreate y OnDestroy de la forma para Activar y Desactivar nuestro Socket, respectivamente:


procedure TfrmServidor.FormCreate(Sender: TObject);
begin
  ServerSocket1.Active := True;
end;

procedure TfrmServidor.FormDestroy(Sender: TObject);
begin
  ServerSocket1.Active := False;
end;

Ya que tenemos a nuestro socket "escuchando", ahora debemos crear código en el evento OnListen del socket del servidor, para que nuestro servidor añada una línea a cada línea que nos llegue. Además de copiarla al Memo, el servidor la enviará al revés (hola - aloh) de regreso al cliente. Hacemos esto último sencillamente para que veamos que algún procesamiento se hace en el lado del cliente.


procedure TfrmServidor.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  sMensaje, sDeCabeza : String;
  i : Integer;
begin

  sMensaje := Socket.ReceiveText;
  sDeCabeza := '';

  // Este for invierte los caracteres del mensaje
  for i := Length(sMensaje) downto 0 do
     sDeCabeza := sDeCabeza + sMensaje[i];

  mmClientes.Lines.Add('"'+sMensaje+'"' + ' de cabeza es "'+sDeCabeza+'"');
  // Envía el menaje "al revés" de regreso al cliente.
  Socket.SendText(sDeCabeza);

end;

Finalmente, añadimos un poco de código a los eventos del socket para que nos actualice cuando clientes se conecten y desconecten.


procedure TfrmServidor.ServerSocket1ClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  mmClientes.Lines.Add('Conexión');
end;

procedure TfrmServidor.ServerSocket1ClientDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  mmClientes.Lines.Add('Desconección');
end;

procedure TfrmServidor.ServerSocket1Listen(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  StatusBar1.Panels.Items[0].Text := 'Escuchando...';
end;

Ahora probemos el sistema. Ejecute el servidor y luego el cliente, y conéctese a la computadora "localhost". Localhost es la computadora local desde donde usted se encuentre. Juegue con el programa. Aquí muestro mi servidor y cliente:

Ahora que sabe que funciona localmente, ejecute el servidor en una máquina en su red y ejecute el cliente en otra, utilizando el nombre de la computadora (o su dirección IP). Apunte muchos clientes al mismo servidor. Corra varios servidores y apunte cinco clientes a cada uno. Diviértase.

Otra cosa que puede hacer para probar que usted está en realidad comunicándose con un servidor en otra computadora es usar telnet como cliente en vez de su propio programa. Simplemente conéctese al puerto 9923 en localhost utilizando Telnet (dentro de su grupo de Accesorios en el menú de programas de Windows) y comience a escribir. Tome en cuenta que Telnet envía cada caracter que usted escribe, así que el "Al reves" sólo servirá si copia y pega texto de otra aplicación (lo cual manda todos los caracteres en la misma cadena de texto).

Ahora usted sabe lo básico acerca de programación de sockets en Delphi. La programación de sockets en sí es lo sencillo, pero lo dificil es el manejar tráfico (lo cual requerirá hilos de ejecución) y la comunicación entre el cliente y el servidor (definir comandos y respuestas, seguridad, etcétera). Pero mientras, nos hemos divertido y aprendido bastante, ¿no cree?

Copiar el Código fuente (17K, formato Zip) para esta sección

Capítulo -->