Anda di halaman 1dari 13

Introduccin a los Sockets en Delphi.

Enrique Gonzlez Alonso-Buenaposada


Introduccin.
Hace poco, una persona que quera programar un desbordamiento de buffer
me mand un mail preguntndome (indirectamente y con muchos rodeos y engaos)
cmo hacerlo. Casi me muero de la risa al leer su cdigo. Una vez corregido, se lo
envi de vuelta, y entonces me dice que no puede hacerse, que los sockets en Delphi
estn mal programados. Lo que tiene uno que or a estas alturas de la vida. Intrigado,
me puse a investigar un poco mas, constatando que todo funciona bien. De paso
escrib esta pequea gua.
Este artculo no est escrito para gente que no tenga una base programando,
bien en Delphi, bien en otros lenguajes, sino para aquellas personas que ya sepan
programar y quieran enterarse de una forma clara de como establecer una conexin
usando Delphi. Espero que sirva de ayuda, porque para eso lo escrib.
Enrique Gonzlez Alonso-Buenaposada.
webmaster@lanssl.com
ndice:
1. Sockets.
2. Cliente, servidor y puertos que intervienen.
3. Crear un socket en Delphi.
3.1. Crear un Socket servidor.
3.2 Crear un socket cliente.
4. Conectar y desconectar los sockets.
4.1. Activar el servidor.
4.2. Conectar el cliente.
4.3. Comprobar si ya estamos conectados.
4.4. La propiedad Active.
5. Obtener informacin de la conexin.
6. Enviar y recibir informacin a travs de los sockets.
6.1. Conexiones Blocking y Non-Blocking.
6.2. Enviar y recibir datos.
6.3. Consejos para programar una aplicacin.
7. El programa de demostracin.
8. Para saber ms.
1. Sockets.
Es muy comn escuchar frases como En TCP-IP, todo funciona con sockets..
Menuda frasecita!. Si buscamos la palabra Socket en un diccionario de ingls nos dir
que es un agujero o abertura al que se puede enchufar algo(Como el zcalo en el que
enchufamos el procesador a la placa base). Esta es una traduccin hecha a lo bestia,
pero nos bastar, porque un socket es una especie de enchufe.
La palabra con la que yo lo designara es conector. El Socket en todo caso,
puede considerarse como el extremo de una conexin. Una vez establecida la
conexin entre un cliente y un servidor, usamos los sockets para enviar o recibir datos
indistintamente. Este asunto no necesita mas explicacin de momento, los detalles se
vern mas adelante.
2. Cliente, servidor y puertos que intervienen.
Lo primero que hay que explicar es cmo se establece una conexin en TCP-
IP. Aunque parezca que no viene mucho al caso, mas adelante quedar claro el
porqu. Lejos de mi intencin explicar todo el proceso de la transmisin pero creo que
es importante explicar como se establece la conexin.
Supongamos que tenemos montada una intranet con TCP/IP y supongamos
que nuestro ordenador cliente (IP 192.168.3.127) quiere establecer una conexin con
un servidor de la misma intranet (IP 192.168.3.100) a travs de HTTP (Generalmente
puerto 80).
Puertos Servicio 0-1023
Puertos Cliente: 1024-65536
Puertos Servicio 0-1023
Puertos Cliente: 1024-65536
SYN
ACK
Puerto X
Puerto 80
SYN/ACK
Cliente Servidor
Lo primero que har el ordenador cliente ser enviar un paquete de
informacin, conocido como SYN, en el que se envan datos tales como su propia
direccin IP y el puerto de origen al servidor. Los puertos del cliente los asigna
automticamente el sistema operativo(En adelante S.O.) del mismo, y estarn en el
rango que hay entre 2
10
(1024) y 2
16
(65536). La peticin va dirigida a un puerto
concreto del servidor, en este caso el 80(HTTP).
El servidor, naturalmente, est escuchando por el puerto 80. Y cuando recibe
el paquete SYN, enva de vuelta un paquete llamado SYN/ACK, que podran
explicarse en realidad como dos paquetes. En primer lugar explicaremos ACK, que es
la abreviatura de ACKNOWLEDGED, con la que informa al cliente que se ha enterado
del paquete SYN que ha recibido. A la vez, enva un paquete SYN como el que el
cliente ha enviado. Este paquete SYN/ACK se enva a la direccin IP y puerto de la
que provena el primer paquete SYN, por el que se supone estar escuchando el
cliente. Hay que hacer notar, que ese puerto estara normalmente cerrado, pero que el
S.O. del cliente lo abre para hacer la peticin.
Finalmente el cliente enva al servidor un paquete ACK al servidor, indicndole
que ha recibido a su vez el paquete SYN/ACK. Si todo este ciclo se completa, la
conexin ha quedado establecida en los dos sentidos. Esto es importante, ya que en
una conexin se puede leer y escribir a la vez de forma asncrona.
Conclusin: En este caso hipottico, quedan fijadas las IPs y los puertos. La
IP del cliente a 192.168.3.127, la del servidor a 192.168.3.100. El puerto cliente(en el
idem) ser variable asignndolo el S.O. en su momento, pero quedando fijo mientras
dure la conexin. El puerto de servicio(en el servidor) ser fijo. El puerto de servicio
estar activo solo mientras dure la conexin, mientras que el del servidor permanecer
a la escucha atento a otras peticiones (bien desde la misma mquina, o desde otras).
3. Crear un socket en Delphi.
Como Delphi es un lenguaje orientado a objetos, todas las operaciones de
sockets se realizarn recurriendo a una clase, TclientWinSocket, que es un puerto a
las Dlls que usa el S.O. para establecer conexiones. Sin embargo para mayor
comodidad, existen las clases TclientSocket y TserverSocket, que descienden de ella,
y nos permiten implementar en cada caso, una conexin cliente o servidor. Ambas
pueden encontrarse en la paleta de componentes, en la pestaa Internet.
Para incluir un objeto de una de estas clases en nuestro programa, bastar con
incluir uno de estos componentes.
Atencin: Hay que tener muy claro que clase de socket queremos crear, bin
cliente, bin servidor. Aunque desde ambos se puede enviar y recibir, es necesario la
existencia del primero para que funcione el segundo. Si no tienes claro que es un
cliente y que es un servidor, vuelve a leerte el punto anterior (2) de este artculo.
3.1. Crear un Socket servidor.
El dato mas importante, en el caso del socket servidor es el del puerto, ya que
una vez activado el mismo, este quedar Escuchando, de forma que le introducimos
el puerto deseado en el object inspector, o directamente:
ServerSocket1.Port:=80; // Por ejemplo.
Atencin: Hay que tener en cuenta que si nuestro ordenador tiene otros
servidores corriendo, estos pueden estar ocupando ya los puertos que queremos usar.
Por ejemplo, si estuviese funcionando un servidor apache (HTTP), con casi toda
probabilidad el puerto 80 estara ocupado (Puede configurarse para otro puerto, pero
no es habitual). Los programas peer-to-peer y las webcam tambin suelen reservar
puertos especficos, ya que establecen conexiones en modo servidor.
Los puertos utilizados (normalmente) por los servidores ms comunes son:
Puerto Servicio
ftp 21
Ssh 22
Telnet 23
Smtp 25
Dns 42
Http 80
Pop3 110
Irc 194
Imap 220
Https 443
Imaps 993
Pop3s 995
Aunque esto puede variar ya que muchos de estos servidores se pueden
configurar para utilizar otros puertos distintos. Adems, existen muchos ms puertos
utilizados por otros servicios. La lista completa de los puertos utilizados por los
distintos servicios puede encontrarse en:
http://www.iana.org/assignments/port-numbers
No obstante, si lo que tenemos es un windows domstico (95-98-ME-XP), no
habr que complicarse demasiado la existencia, bastando con que el puerto de
servicio sea un nmero mayor que 20.
3.2 Crear un socket cliente.
Para este, el dato mas importante es la IP a la que queremos conectar, junto al
puerto del servidor, que esperamos que est escuchando. La IP se la podemos dar en
el object inspector, aunque es mejor hacerlo en tiempo de ejecucin, ya que un cliente
debera conectarse en tiempo de ejecucin. Lo mismo puede decirse del puerto.
ClientSocket1.Address:= 192.168.3.127; // Por ejemplo
ClientSocket1.Port:=80; // Por ejemplo.
4. Conectar y desconectar los sockets.
Bin, hasta ahora hemos visto que para crear una aplicacin que tenga un
socket cliente o servidor bastar con incluirlo desde la paleta de componentes.
Tambin hemos visto como darle los valores necesarios. Todo ello es bastante simple
si se tiene claro lo que se est haciendo. Crear la conexin es sencillo tambin.
4.1. Activar el servidor.
Para activar el servidor, bastar con usar el procedimiento open:
ServerSocket1.port:=80; // Damos el puerto.
ServerSocket1.Open; // Conectamos.
De esta forma el puerto que hayamos elegido para la conexin quedar
Escuchando en espera de una conexin. Para desactivarlo usaremos el
procedimiento close.
ServerSocket1.close;
4.2. Conectar el cliente.
Al igual que ocurre con el servidor para conectar y desconectar el cliente
usaremos los procedimientos Open y Close:
ClientSocket1.Address:= 192.168.3.127; // Le damos una IP
ClientSocket1.Port:=80; // Especificamos el puerto al que debe
// conectarse.
ClientSocket1.Open; // Abrimos la conexin.
:
:
:
ClientSocket1.Close; // Cerramos la conexin.
Si el servidor no estuviese escuchando, o no nos permitiese la conexin,
recibiramos el error de socket correspondiente.
4.3. Comprobar si ya estamos conectados.
Para comprobar si ya estamos conectados, bastar con consultar el flag
Connected del tipo boolean, que estar en TRUE si la conexin ya est establecida,
y a False de no ser as. Esto nos puede evitar, por ejemplo, conectar el cliente si ya
est conectado:
If not ClientSocket1.Socket.Connected then Clientsocket1.Open;
4.4. La propiedad Active.
Otra forma abrir la conexin es que nuestro socket est activo desde que
arranca la aplicacin. Para ello usaremos la propiedad Active, que encontramos en el
Object Inspector y que normalmente est puesta a FALSE.
Si nuestro socket es servidor ACTIVE=TRUE har que est escuchando desde
el inicio de la aplicacin. Si es cliente, intentar establecer la conexin desde el inicio.
Otra cosa que podemos hacer es con active es cerrar las conexiones. Si
ponemos (en tiempo de ejecucin) ACTIVE=FALSE la conexin abierta se cerrar. Si
lo hacemos sobre un socket servidor, adems, cerrar todas las conexiones activas
(Puede tener varias), haciendo que deje de escuchar por el puerto que le habamos
asignado.
5. Obtener informacin de la conexin.
Una vez la conexin est establecida, podemos usar las propiedades
LocalHost y LocalPort para obtener la direccin IP y el puerto usados por ambos,
cliente y servidor. Tambin se puede usar la propiedad Handle para obtener un
controlador directo a la conexin.
6. Enviar y recibir informacin a travs de los sockets.
Esta es la parte mas complicada (a mi entender) de todo el asunto. Lo es
porque la gama de posibilidades es enorme, y todas ellas son correctas para un uso
concreto. Explicarlas todas escapa a la intencin de este artculo, de forma que
intentar explicar las principales por encima. No obstante recomiendo al lector que
busque mas informacin y experimente, dependiendo de sus necesidades.
6.1. Conexiones Blocking y Non-Blocking.
Como qued dicho anteriormente al final del captulo 2, la lectura y escritura
pueden funcionar de forma independiente una de la otra. Esto es posible en las
conexiones non-blocking. En las conexiones Blocking, nos encontramos que hasta
que no haya terminado una operacin (Bin de lectura o escritura) no se puede
realizar la siguiente.
La propiedad que determina que tipo de conexin estamos usando, en cada
caso, se llama ClientType para un socket cliente y ServerType para un servidor. Esta
propiedad la podemos encontrar en el Object Inspector.
6.2. Enviar y recibir datos.
Lo primero que hay que tener en cuenta es el tipo de informacin que se quiere
enviar o recibir. Si vamos a leer algo realmente grande, podemos usar mtodos como
SendBuf/ReceiveBuf o SendStream/ReceiveStream. Como no es mi intencin explicar
como funcionan los buffers y streams, no explicar mas estos mtodos. El lector que
sepa como funcionan estas formas de trabajar con datos no tendr dificultad en usar
con estos mtodos una vez haya concluido este captulo.
Readln/SendLn es otra forma de enviar datos. Se envan y se reciben datos
hasta que aparece un carcter especificado como parmetro, aunque personalmente
prefiero SendText/ReceiveText.
ClientSocket1.Socket.SendText (st);
SendText/ReceiveText se puede enviar el contenido de una variable del tipo
String. Como las variables de este tipo tienen un tamao dinmico, se pueden usar
para enviar casi cualquier cosa. En una variable de este tipo podemos cargar un
archivo de cualquier tipo, que quedar idntico al grabarlo. Mediante este
procedimiento he llegado a enviar y recibir un archivo de 40 mb sin problemas (Se
cada vez mas lento a partir de los 4 mb, pero en general funcionaba bien.). No
obstante, para cosas grandes, recomiendo evitar las chapuzas y emplear variables del
tipo stream, con las que podemos enviar directamente desde un archivo.
Recibir es un poco mas complejo, pero solamente un poco. Como nuestro
socket queda establecido, tenemos que esperar a un evento del tipo ClientRead.
Crearemos el procedimiento asociado con el Object Inspector, que tendra el siguiente
aspecto:
procedure TForm1.ClientSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var st:string;
begin
st:=Socket.ReceiveText; // Ojo, tener en cuenta que se recibe
: // de Socket.ReceiveText
: // no de ClientSocket1.socket.ReceiveText
: // la razn hay que buscarla en el
: // encabezado del procedimiento
end;
6.3. Consejos para programar una aplicacin.
Como se ha visto, el socket es el extremo de una conexin, a travs del cual se
pueden enviar y recibir datos. Esto tiene varias aplicaciones, no solamente enviar
datos a travs de la red, sino por ejemplo el envo de datos entre dos aplicaciones que
estn funcionando en el mismo ordenador.
Es fundamental que haya un servidor adecuado funcionando para probar una
aplicacin cliente. Esto plantea un problema. Cmo programar, por ejemplo, un
cliente apache si solamente disponemos de un ordenador? La respuesta es sencilla,
usaremos la IP de intranet de nuestro propio ordenador. Ponemos el servidor a
funcionar en nuestra mquina mientras se programa la aplicacin.
Qu no tenemos una intranet montada? No hay problema, podemos hacer lo
mismo, empleando la IP de loopback que tenga la mquina, normalmente 127.0.0.1.
Con esta IP, normalmente estaremos accediendo a nuestro mismo ordenador.
Otra cosa a tener en cuenta, es que a la hora de programar un servidor
deberamos evitar que haya varias instancias del mismo funcionando. Esto puede
hacerse de varias formas. Tambin es muy importante no dejar los sockets abiertos
cuando la aplicacin finalice.
7. El programa de demostracin.
El programa que se incluye con este artculo pone en marcha un socket cliente
y uno servidor. Con el cliente se enva informacin (texto), mientras que con el
servidor se recibe. Al incluir los dos sockets, el programa puede intercambiar texto con
otro programa en otro ordenador.
Lo he probado tanto con la IP 127.0.0.1, como con la direccin de la misma
mquina en la intranet. En ambos casos, lo escrito en el memorando de la izquierda se
transmite al de la derecha. Tambin est probado desde varias direcciones de una
intranet, pudiendo intercambiar texto con otros ordenadores. Para hacerlo as, el
servidor al que vamos a conectar debe estar encendido (Una copia del programa
corriendo). Escribimos la IP de nuestro objetivo, pulsamos el botn Conectar y ya
est listo para enviar texto.
El programa evita que se ejecuten varias instancias del mismo recurriendo a un
semforo (Ver archivo dpr).
El socket servidor arranca con el evento OnCreate del formulario principal,
mientras que el cliente (el que enva texto) solamente enva una vez se haya escrito
una IP (Correcta) y se pulse el botn conectar.
El programa se pens originalmente para intercambiar texto entre dos
ordenadores, pero el funcionamiento del mismo permite interconexiones extraas,
como por ejemplo:
A
E
D
C
B
En donde el ordenador A no recibe texto de nadie y enva a B. B recibe de A, y
enva a C. D y E intercambian entre ellos, pero E recibe tambin de C.
Por ltimo debe observarse que se usa el evento OnClose del formulario
principal para cerrar los sockets. No explicar mas la aplicacin ya que despus de
estas explicaciones, bastar con echarle un vistazo al mismo para comprender que
hace y como funciona.
8. Para saber mas.
En este artculo se puede leer una introduccin al uso de sockets en Delphi,
pero que nadie piense que est todo dicho. En el no est ni la mitad de lo que yo
mismo s, y por supuesto hay personas que saben mucho mas del tema que yo. Lo
que hay aqu escrito, como el propio ttulo del artculo sugiere, no es mas que una
breve introduccin a este tema.
Si alguien quiere saber mas, le recomiendo que empiece por la propia ayuda
del Borland Delphi, pero que no pare ah. Para continuar, podemos echar un buen
vistazo al cdigo fuente de algunos componentes incluidos en el propio Delphi, como
los INDY components, que son un buen ejemplo de cmo implementar los protocolos
mas comunes usando sockets. El cdigo fuente de algunos programas peer-to-peer
puede ser otro buen sitio para aprender, si a uno no le importa ver cdigo escrito para
otros compiladores. Todos ellos trabajan con las mismas dlls de Windows.
Y por supuesto existen toneladas de literatura al respecto. Desde artculos
como este hasta libros dedicados al tema. En todos ellos se hace un estudio mas
detallado sobre los temas tratados en este artculo y de otros que se han quedado en
el tintero.

Anda mungkin juga menyukai