Manual de Sockets


Hola Amigos, durante los siguientes capítulos veremos como podemos construir Sockets en Dephi y como siempre empezaremos con un poco de teoría para aquel que no sepa que es un Socket o para que sirva pues lo entienda.

Los Sockets son puntos finales de enlaces de comunicación entre procesos,  los cuales se tratan como descriptores de archivos, de forma que se pueden intercambiar datos con otros procesos transmitiendo y recibiendo a través de ese socket.

El tipo de socket describe la forma en la que se transfiere información a través de ese socket.

Tipos de Sockets

Sockets TCP (Transport Control Protocol): Es un servicio orientado a conexión donde los datos se transfieren sin encuadrarlos en registros o bloques. Si se rompe la conexión entre los procesos, éstos serán informados.


El protocolo de comunicaciones TCP es un protocolo orientado a conexión, ya que para establecer una comunicación utilizando el protocolo TCP, hay que establecer en primer lugar una conexión entre un par de sockets. Mientras uno de los sockets atiende peticiones de conexión "Servidor", el otro solicita una conexión "cliente". Una vez que los dos sockets estén conectados, se pueden utilizar para transmitir datos en ambas direcciones.

Sockets UDP (UDP, User Datagram Protocol): Es un servicio de transporte sin conexión. Se transmiten paquetes individuales de información y no garantiza que los paquetes llegarán en alguna forma en particular. De hecho los paquetes pueden perderse, duplicarse e incluso llegar en desorden.


El protocolo de comunicaciones UDP es un protocolo sin conexión,  cada vez que se envíen datagramas es necesario enviar el descriptor del socket local y la dirección del socket que debe recibir el datagrama. Como se puede ver, hay que enviar datos adicionales cada vez que se realice una comunicación.

Los servicios sin conexión generalmente ofrecen mayor velocidad pero menor confiabilidad que los servicios TCP.

Delphi es un lenguaje orientado a objetos por lo tanto todas las operaciones de sockets se realizarán recurriendo a la clase  TclientWinSocket, que es un puerto a las Dll's que usa el S.O. para establecer conexiones. Sin embargo para hacernos la vida menos pesada existen las clases TclientSocket y TserverSocket, que descienden de ella, y nos permiten implementar en cada caso, una conexión cliente o servidor.

Antes que nada debemos de ver que tipo de Socket queremos  crear un cliente o un servidor, ya que son diferentes, además sin el servidor no te funcionara el cliente.

Los componentes TClientSocket y TServerSocket estan en la Ficha Inernet.


 Socket servidor

En el caso del socket servidor  lo mas importante es el del puerto, debido a  que una vez activado  este quedará "Escuchando" de tal forma que le debemos indicar el puerto en su propiedad Port, o si lo prefieres por código seria así:

ServerSocket1.Port:=80; //Suponiendo que utilizaremos el puerto Http.

Hay que tener cuidado, ya que si tenemos otros servidores activos en nuestro sistema quizás ya se estén ocupando los puertos que queramos utilizar.

Socket cliente

En este caso lo mas importante es la IP a la que queremos conectar y el puerto del servidor que nos atenderá, la IP se la puedes dar en la propiedad Adress del ClientSocket y el puerto en la propiedad Port. Si lo quisieras hacer mediante código seria como sigue:

ClientSocket1.Address:= '10.10.160.209'; // Dirección de mi Server FTP
ClientSocket1.Port:=21;

 

Puertos y Servicios

El protocolo TCP/IP tiene diferentes puertos, el paquete de datos tiene dentro de sus metadatos el número de puerto donde deberá enviar los bytes a la computadora  destino, una vez que la implementación TCP/IP en la computadora  destino recibe los bytes, lo primero que hace es revisar a qué puerto debe  asignarlo.

Hay varios servicios estándar, que están especificados en el documento RFC #1700. De hecho se  puede asignar cualquier servicio a cualquier puerto para sus propios propósitos, pero si  no se siguen los estándares  será más difícil a los clientes hablar con nosotros.

Nota: Todos los servicios tienen algo en común ya que  redireccionan stdin y stdout.

A continuación se presentara una lista con los puertos y sus servicios mas utilizados en Internet:

Servicio Puerto
Telnet 23
Smtp 25
Pop 110
Ftp 20/21
Http o Web 80
Nntp 119
Irc 194

Ahora veremos como podemos echar a andar los sockets.

Para que el servidor se active solo será necesario  usar el procedimiento Open tal y como se muestra a continuación:

ServerSocket1.port:=21;
ServerSocket1.Open; //Abrimos el Socket

Nota: También podemos abrir el puerto poniendo la propiedad Active en True y esto es valido para los clientes y servidores.

Así el puerto que hayamos elegido para la conexión quedará "Escuchando" en espera de una conexión de algún cliente, por cierto para desactivarlo usaremos el procedimiento close de esta forma: ServerSocket1.close;


Para conectar y desconectar el cliente usaremos los procedimientos Open y Close similarmente como lo hicimos con el servidor.

ClientSocket1.Address:= '10.10.160.209';
ClientSocket1.Port:=21; .
ClientSocket1.Open; //Se abre la conexión..
{Líneas de código, relacionadas al enfoque del Socket.}
ClientSocket1.Close; // se cierra la conexión.

En caso de que el servidor no este funcionando, se recibirá u error de conexión. Pero no te preocupes todos esos eventos pueden ser controlados desde el inspector de objetos.

Para saber si estamos conectados, consultaremos la bandera "Connected" de tipo boolean la cual estará en TRUE si la conexión ya está establecida y en False si no se esta conectado, esto nos era útil para no tratar de conectarnos si ya estamos conectados.  Veamos como podríamos lograrlo

If not ClientSocket1.Socket.Connected then Clientsocket1.Open;

Envió de Información

Se nos ponemos a analizar lo ya explicado, nos damos cuenta que entonces todo funciona través de Sockets, solo que existen herramientas que nos facilitan el trabajo, por lo tanto la utilidad de un Socket es muy amplia, debido a que se pueden realizar muchas cosas a través de ellos, pero por lo pronto se explicara dos tipos de conexiones:
 

Conexiones Blocking / Non-Blocking . . . La lectura y escritura pueden funcionar de forma independiente una de la otra, lo cual  es posible en  conexiones "non-blocking". En  conexiones "Blocking", hasta que no haya terminado una operación ya sea de lectura o escritura, no se puede realizar la siguiente.

Ahora la propiedad que determina que tipo de conexión estamos usando, se llama ClientType para un socket cliente y ServerType para un servidor y pueden ser modificadas desde el Inspector de Objetos.


Hay que tener en cuenta que tipo de información se va a enviar o recibir, ya que existen procedimientos para tratar transferencias de archivos muy grandes, pero nosotros empezaremos por algo sencillo como por ejemplo enviar y recibir cadenas de caracteres.

 SendText y ReceiveText nos permiten enviar y recibir datos hasta que aparece un carácter especificado como parámetro, por cierto también existen Readln y SendLn que tienen la misma funcionalidad. La forma de utilizar estas funciones seria como sigue:

ClientSocket1.Socket.SendText (Edit1.Text);

En donde Edit1.Text contiene una cadena de caracteres previamente capturada. En caso de que se quiera enviar archivos de gran tamaño es aconsejable que se utilicen variables de tipo Stream.

Ahora veremos como podemos recibir información. Debido a que nuestro socket queda establecido tendremos que esperar en un evento del tipo ClientRead, por lo tanto ahí es donde ira nuestro código:

procedure TForm1.ClientSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
     Var Texto : String;
begin
     Texto := Socket.ReceiveText; //En Texto se recibe la cadena leída.
end;


Es hora de realizar un ejemplo de como podríamos utilizar los sockets, será un sencillo ejemplo con el único fin de ejemplificar el uso de los sockets.

Arranca una nueva aplicación en Delphi, en el Caption del Form ponle Sockets, Coloca un Label que diga Charla, después coloca un Memo y su propiedad ReadOnly ponla en True.

Debajo del Memo coloca Un Edit, Borra el contenido de su propiedad Text y ajústalo a lo ancho del Memo.

Pon un SpeedButton y en su caption ponle Enviar, después coloca un TPanel en el Form, en su propiedad Align ponle alTop, con esto se ajustara hacia la parte superior del Form, borra el contenido de la propiedad Caption.

Dentro del Panel coloca un Label que diga I.P. Servidor, después coloca un Edit a un costado del Label y en su propiedad Text ponle 127.0.0.1, esta I.P. es la de tu maquina local también conocida como LocalHost. Por ultimo coloca un SppedButton a un costado del Edit, y en su Caption ponle Conectar.

Ahora ve a la ficha Internet y coloca sobre el Form un componente TClientSocket, en su propiedad Port ponle 210, después coloca un componente TServerSocket y en su propiedad Port ponle 210.

Muy bien el diseño seria como sigue:

Ahora te daré el código.

Evento Oncreate del Form:

procedure TForm1.FormCreate(Sender: TObject);
begin
//El servidor se Activa.
//En tiempo de diseño se le asigno su
//puerto.
ServerSocket1.Open;
StatusBar1.SimpleText :='Servidor listo en el puerto 210...';
end;

 

Evento OnClose del Form:

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
StatusBar1.SimpleText := 'Cerrando los socket . . .';
Serversocket1.Close;
if clientSocket1.Socket.Connected then
clientsocket1.Close;
sleep(2000);
end;

 

Código del botón Conectar:

procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
// se conecta el ClientSocket1.
if clientsocket1.Socket.Connected then
StatusBar1.SimpleText := 'El Socket ya esta conectado . . .'
else
begin
clientSocket1.Address:= Edit2.Text;
clientsocket1.Open; //Mas recomendable que el método Active
StatusBar1.SimpleText := 'Abriendo la conexion cliente...';
end;
end;

 

Código del Botón Enviar:

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
if clientsocket1.Socket.Connected then
begin
//se envia el texto
ClientSocket1.Socket.SendText(Edit1.Text);
StatusBar1.SimpleText := 'Enviando...';
Edit1.Clear;
end
else
StatusBar1.SimpleText := 'No se puede enviar.';
end;
 

Evento OnAccept del ServerSocket:

procedure TForm1.ServerSocket1Accept(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText := 'Conexion aceptada de : '+ Socket.RemoteAddress;
end;

 

Evento OnClientRead del ServerSocket:

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
Var Texto : String;
begin
//Recibe la informacion del Socket
StatusBar1.SimpleText := 'Recibiendo Datos ...';
Texto := Socket.ReceiveText;
Memo1.Lines.Add(Texto);
end;
 

Evento OnConnect del ClientSocket:

procedure TForm1.ClientSocket1Connect(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText := 'Cliente Conectado.';
end;
 

Evento OnDisconnect del ClientSocket:

procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
StatusBar1.SimpleText := 'Cliente Desconectado.';
end;

 


Con esto hemos concluido el tema de Sockets, y como es costumbre les pongo a su disposición el código fuente de este ejercicio.

CÓDIGO FUENTE DE LOS SOCKETS

Si tienes algún comentario o deseas compartir alguna información da Click Aquí.....