Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
ARQUITECTURA
CLIENTE-SERVIDOR (SOCKETS)
J
A
P ERL V
ASCAL
A
INTRODUCCIÓN
Este informe tiene por objetivo explicar el uso del SOCKETS, sistema de comunicación entre procesos,
para una red local o internet.
Para ello, abordaremos 3 tipos de lenguajes de programación PERL, JAVA, PASCAL, donde podremos
ver sintaxis y estructura, además de un ejemplo de comunicación entre el servidor y un cliente.
Socket designa un concepto abstracto por el cual dos programas (posiblemente situados en
computadoras distintas) pueden intercambiarse cualquier flujo de datos, generalmente de manera fiable
y ordenada. Un socket queda definido por una dirección IP, un protocolo y un número de puerto.
Para que dos programas puedan comunicarse entre sí es necesario que se cumplan ciertos requisitos:
• Que un programa sea capaz de localizar al otro.
• Que ambos programas sean capaces de intercambiarse cualquier secuencia de datos relevantes a
su finalidad.
Para ello son necesarios los tres recursos que originan el concepto de socket:
• Un protocolo de comunicaciones, que permite el intercambio de datos.
• Una dirección del Protocolo de Red (Dirección IP, si se utiliza el Protocolo TCP/IP), que
identifica una computadora.
• Un número de puerto, que identifica a un programa dentro de una computadora.
SOCKETS EN PERL
Se trata de un primer diálogo informativo entre cliente y servidor que permita establecer una conexión
entre ellos.
Lo que hay que resolver, concretamente, es que el servidor pueda tener permanentemente un socket a la
escucha y que la negociación inicial de una sesión entre el cliente y el servidor no limite al servidor la
capacidad de atender más peticiones. Es una situación muy habitual, así que no debe ser causante de
ningún trastorno: el servidor ofrecerá siempre un mismo socket de número conocido, por el que
entrarán las nuevas peticiones y a las que dedicará sólo unos segundos cada vez.
Existen muchas formas de crear un socket en perl, aquí se muestran conceptos importantes para poder
entender los códigos.
$protocol = getprotobyname('tcp');
Asignara al protocolo los bytes correspondientes para su uso como tcp, en palabras simples especifica
que se va a utilizar el protocolo tcp y lo introduce en $protocol.
$siteaddr = (gethostbyname($host));
Resuelve el host en la variable $host, es decir obtiene la ip y la introduce en $siteaddr.
SERVIDOR
En Perl, una secuencia válida para abrir un socket de escucha sería:
$portescucha=1080;
socket (EscuchaServer,PF_INET,SOCK_STREAM,getprotobyname('tcp'))
or die "socket: $!\n";;
setsockopt(EscuchaServer,SOL_SOCKET,SO_REUSEADDR,pack("l",1))
or die "setsockopt: $!\n";
bind (EscuchaServer,sockaddr_in($portescucha,INADDR_ANY))
or die "bind: $!\n";
listen (EscuchaServer,SOMAXCONN) or die "listen: $! \n";
($p,$ip)=sockaddr_in(getsockname(EscuchaServer));
print "Servidor escuchando en el puerto $p del sitio ",inet_ntoa($ip),"\n";
print "Esperando cox...\n";
accept(ClienteActual,EscuchaServer);
La función «accept» de Perl, es bloqueante, es decir, el servidor queda suspendido aquí mientras
ningún cliente llega. Posteriormente, a esta instrucción (ya ha llegado un cliente) el servidor podrá
comunicarse con aquél haciendo:
sysread(ClienteActual,$datosentrantes,255);
syswrite(ClienteActual,$datossalientes,255);
La conexión es bidireccional, de manera que si se cuida que el ritmo del diálogo sea el mismo para
ambos, puede utilizarse sin problemas el mismo socket.
En la parte cliente habría que hacer:
$iaddrsocket=$ip_server;
$portsocket=$port_server;
$aux=inet_aton($iaddrsocket);
$paddrsocket=sockaddr_in($portsocket,$aux);
socket(SocketCliente,PF_INET,SOCK_STREAM,getprotobyname('tcp'))
or return((-1,"socket: $!\n"));
connect(SocketCliente,$paddrsocket) or return((-1,"connect: $!\n"));
CLIENTE
En perl el cliente seria de la siguiente forma
#!/usr/bin/perl -w
use Socket;
my ($remote,$port, $iaddr, $paddr, $proto, $line);
$remote = 'localhost';
$port = 5000;
if ($port =~ /\D/) { $port = getservbyname($port, 'tcp') }
die "No Puerto" unless $port;
$iaddr = inet_aton($remote) || die "No Host: $remote";
$paddr = sockaddr_in($port, $iaddr);
$proto = getprotobyname('tcp');
socket(SOCK, PF_INET, SOCK_STREAM, $proto) || die "socket: $!";
connect(SOCK, $paddr) || die "connect: $!";
while (defined($line = <SOCK>))
{ print $line; }
close (SOCK) || die "close: $!";
exit;
Definición por partes:
use Socket;
//Se usa la libreria Socket y strict.
my ($remote,$port, $iaddr, $paddr, $proto, $line);
//Definine las variables $remote,$port, $iaddr, $paddr, $proto, $line.
$remote = 'localhost';
$port = 666;
//Establece la configuraciones de el host y puerto.
If ($port =~ /\D/) { $port = getservbyname($port, 'tcp') }
die "No Puerto" unless $port;
//Revisa si hay puerto definido, y si no imprime "No Puerto".
$iaddr = inet_aton($remote) || die "No Host: $remote";
$paddr = sockaddr_in($port, $iaddr);
//Primero traduce el nombre, y despues especifica el puerto al socket.
socket(SOCK, PF_INET, SOCK_STREAM, $proto) || die "socket: $!";
connect(SOCK, $paddr) || die "connect: $!";
//Crea el socket y conecta.
while (defined($line = <SOCK>)) {
print $line;
}
close (SOCK) || die "close: $!";
exit;
Imprime lo que diga el server, cierra el socket, y sale.
JAVA
Las aplicaciones Java están típicamente compiladas en un bytecode (El bytecode es un código
intermedio más abstracto que el código máquina.), aunque la compilación en código máquina nativo
también es posible. En el tiempo de ejecución, el bytecode es normalmente interpretado o compilado a
código nativo para la ejecución, aunque la ejecución directa por hardware del bytecode por un
procesador Java también es posible.
La implementación original y de referencia del compilador, la máquina virtual y las librerías de clases
de Java fueron desarrollados por Sun Microsystems en 1995. Desde entonces, Sun ha controlado las
especificaciones, el desarrollo y evolución del lenguaje a través del Java Community Process, si bien
otros han desarrollado también implementaciones alternativas de estas tecnologías de Sun, algunas
incluso bajo licencias de software libre.
Entre noviembre de 2006 y mayo de 2007, Sun Microsystems liberó la mayor parte de sus tecnologías
Java bajo la licencia GNU GPL, de acuerdo con las especificaciones del Java Community Process, de
tal forma que prácticamente todo el Java de Sun es ahora software libre (aunque la biblioteca de clases
de Sun que se requiere para ejecutar los programas Java todavía no es software libre).
SOCKETS EN JAVA
Los sockets son un sistema de comunicación entre procesos de diferentes máquinas de una red. Más
exactamente, un socket es un punto de comunicación por el cual un proceso puede emitir o recibir
información. Fueron popularizados por Berckley Software Distribution, de la universidad
norteamericana de Berkley. Los sockets han de ser capaces de utilizar el protocolo de streams TCP
(Transfer Contro Protocol) y el de datagramas UDP (User Datagram Protocol).
Utilizan una serie de primitivas para establecer el punto de comunicación, para conectarse a una
máquina remota en un determinado puerto que esté disponible, para escuchar en él, para leer o escribir
y publicar información en él, y finalmente para desconectarse. Con todas las primitivas se puede crear
un sistema de diálogo muy completo.
EJEMPLOS
// configurar GUI
public Servidor()
{
super( "Servidor" );
// crear areaPantalla
areaPantalla = new JTextArea();
contenedor.add( new JScrollPane( areaPantalla ),
BorderLayout.CENTER );
while ( true ) {
try {
esperarConexion(); // Paso 2: esperar una conexión.
obtenerFlujos(); // Paso 3: obtener flujos de entrada y salida.
procesarConexion(); // Paso 4: procesar la conexión.
}
// habilitar campoIntroducir para que el usuario del servidor pueda enviar mensajes
establecerCampoTextoEditable( true );
try {
salida.close();
entrada.close();
conexion.close();
}
catch( IOException excepcionES ) {
excepcionES.printStackTrace();
}
}
// crear areaPantalla
areaPantalla = new JTextArea();
contenedor.add( new JScrollPane( areaPantalla ),
BorderLayout.CENTER );
finally {
cerrarConexion(); // Paso 4: cerrar la conexión
}
// conectarse al servidor
private void conectarAServidor() throws IOException
{
mostrarMensaje( "Intentando realizar conexión\n" );
try {
salida.close();
entrada.close();
cliente.close();
}
catch( IOException excepcionES ) {
excepcionES.printStackTrace();
}
}
if ( args.length == 0 )
aplicacion = new Cliente( "127.0.0.1" );
else
aplicacion = new Cliente( args[ 0 ] );
aplicacion.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
aplicacion.ejecutarCliente();
}
PASCAL
Pascal es un lenguaje de programación desarrollado por el profesor suizo Niklaus Wirth a finales de los
años 60. Su objetivo era crear un lenguaje que facilitara el aprendizaje de la programación a sus
alumnos. Sin embargo con el tiempo su utilización excedió el ámbito académico para convertirse en
una herramienta para la creación de aplicaciones de todo tipo.
Pascal se caracteriza por ser un lenguaje de programación estructurado secuencial, selectiva e iterativa,
fuertemente tipificado. Esto implica que:
1. El código está dividido en porciones fácilmente legibles llamadas funciones o procedimientos.
De esta forma Pascal facilita la utilización de la programación estructurada en oposición al
antiguo estilo de programación monolítica.
2. El tipo de dato de todas las variables debe ser declarado previamente para que su uso quede
habilitado.
El nombre de Pascal fue escogido en honor al matemático Blaise Pascal.
EJEMPLOS
A continuación veremos un ejemplo de cómo programar en PASCAL un servidor de números
telefónicos, solicitados por el cliente.
Program Telserver(Input,Output)
Constant
Maxbuf=4;
Servername: ‘TelServ’;
Type
Netname=array[1..16] of char;
Nameorbufinfo= record
Case Boolean of
False: (name : netname);
True: (NexBufLen: Word;
NexBufPtr: pionter);
END;
Ncb = record
Command, retcode,
Localsessionnumber, localnumberbyte: byte;
Bufptr: pointer;
Callname: nameorbufinfo;
Name: netname;
Recivetimeout, Sendtimeout: byte;
Post: pointer;
LAN_Number: 0..1;
Cmd_complete:byte;
Reserved: array[1..14] of byte;
End;
Var
Recivebufs : array [1..Mabuf] of ncb;
Sendbuf: ncb;
Telno: string;
Function netbios (var n: nbc): byte assembler
Begin
Asm
Pop bx;
Pop es;
Int $5c; //interrumpe la llamada a netbios
End;
End; //fin netbios
Procedure sendbackphone;
Begin
Whit sendbuf do
Begin
Repeat until cmd_complete <> command_pending;
If cmd_complete <> good_return then
Servererror;
Telno:=servername+’:’+telno;
Bufptr:= addr(telno);
Case netbios (sendbuf) of
Good_return, command_pending;
Else servererror;
End;
End;
End; //sendbackphone
Procedure servererror;
Begin
End;
//Programa principal
Begin
Sendbuf.command:=addgroupname;
Sendbuf.name := ‘telserv’;
{$X+}
Netbios(sendbuf);
{$X-}
While true do
For i:=1 to Maxbuf do
Whit recivebuf[i] do
Case cmd_complete of
Command_pending :;
Good_return:
Begin
Searchbuf(bufptr);
Sendbackphone;
Case netbios (recivebuf [i]) of
Good_return, command_pending;
Else servererror;
End;
End;
End;
Procedure clienterror;
Begin
End;
//Programa principal
Begin
Sendbuf.command := senddatagram;
Sendbuf.ptr := addr (telno);
Sendbuf.name := ‘Telserv’;
{$X+}
Netbios(sendbuf);
{$X-}
For i:=1 to Maxbuf do
With recivebuf[i] do
Case cmd_complete of
Command_oendig;
Good_return;
Begin
Writeln(bufptr);
Case netbios(recivebuf[i]) of
Good_return,command_pendig;
Else clienterror;
End;
End;
End;
CONLUSIÓN