Anda di halaman 1dari 39

PRCTICA 2: MANUAL DE SOCKETS EN C

ARQUITECTURA DE REDES
Laboratorio
Grado en Ingeniera Informtica
Curso 2014/15
Laboratorio de Arquitectura de Redes
- 2 -
NDICE
1. INTRODUCCIN .......................................................................... 3
1.1 La familia de protocolos TCP/IP. ................................................ 3
1.2 Nivel de red (IP). ......................................................................... 3
1.3 Nivel de transporte (TCP, UDP). ................................................ 4
2. SOCKETS EN C ........................................................................... 4
2.1. Conceptos bsicos. ................................................................... 4
2.2 Dominios de comunicacin. ....................................................... 6
2.3 Tipos de sockets. ........................................................................ 7
2.4 Ordenacin de los bytes. ............................................................ 7
2.5 Servicio orientado a conexin (TCP) ......................................... 8
2.5.1 El modelo utilizado ................................................................... 8
2.5.2 Resumen de llamadas al sistema. .......................................... 9
2.6. Creacin de un socket ............................................................... 10
2.6.1 Estructuras de datos ............................................................... 11
2.6.2 Asociacin de un socket a unos parmetros determinados... 12
2.6.3 Habilitar un socket para recibir peticiones de conexin.......... 14
2.6.4 Aceptar peticiones de conexin ............................................ 14
2.6.5. Lanzar peticiones de conexin ............................................. 16
2.6.6 Conexin entre los sockets del cliente y servidor.................. 17
2.6.7 Enviar y recibir datos a travs de un socket TCP.................. 17
2.6.8 Cierre de un socket .................................................................. 19
2.7 Diagrama de estados de una conexin TCP............................. 20
2.8 Servicio no orientado a conexin (UDP)..................................... 21
2.8.1 El modelo utilizado ................................................................... 21
2.8.2 Enviar y recibir datos a travs de un socket UDP................. 22
3. OTRAS FUNCIONALIDADES...................................................... 24
3.1 Funcin gethostname.................................................................. 24
3.2 Creacin de un proceso hijoFuncin fork.................................. 25
3.3 Servidores TCP concurrentes y secuenciales............................ 26
3.4 Servidores UDP concurrentes y secuenciales........................... 27
4. EJ EMPLO...................................................................................... 28
4.1 Introduccin.................................................................................. 28
4.2 Descripcin del programa Servidor............................................. 28
4.3 Descripcin del programa Cliente............................................... 31
4.4 Descripcin de Servidor concurrente y secuencial..................... 33
4.5 Listados completos de cdigo..................................................... 36
4.6 Bibliografa 39
Laboratorio de Arquitectura de Redes
- 3 -
1. INTRODUCCIN
1.1 La familia de protocolos TCP/IP.
La familia de protocolos TCP/IP fue creada a finales de los aos 60 cuando an no se
haba definido el modelo OSI. Consta de una serie de protocolos que cubren todos los
niveles OSI uniendo varios de ellos.
Figura 1-1: Familia TCP/IP y niveles OSI
Los niveles 5-7 de OSI se incluyen dentro de los servicios al usuario ofrecidos
por la familia TCP/IP:
El nivel 4 se corresponde con Transmission Control Protocol (TCP) y User
Datagram Protocol (UDP) que cubren el nivel de transporte dando servicios con
caracteristicas distintas.
Internet Protocol (IP): se corresponde con el nivel 3 de red de OSI.
Data Link Layer, cubre los niveles 1 y 2 de OSI. Existen multitud de protocolos
usados por TCP/IP ya que tambin existen muchos canales fsicos de
comunicacin que permiten la conexin entre dos mquinas: lneas telefnicas,
Ethernet, token ring, lnea serie...
1.2 Nivel de red (IP).
El protocolo IP de nivel de red nos proporciona un servicio sin conexin y no seguro
(connectionless, datagram service).
Para comprender qu es un servicio sin conexin lo compararemos con el servicio
postal. Cada mensaje lleva consigo las direcciones completas de origen y destino, por
lo que cada uno de ellos se puede encaminar de forma independiente a travs del
Laboratorio de Arquitectura de Redes
- 4 -
sistema. Al igual que en correos, un mensaje puede sufrir ciertos retardos
independientes del resto de mensajes por lo que dos mensajes con el mismo origen y
destino pueden recibirse en distinto orden a como se enviaron.
No es un servicio seguro ya que no garantiza que todos los mensajes lleguen a su
destino o que lleguen correctamente. Esta ser tarea de los niveles superiores.
1.3 Nivel de transporte (TCP, UDP).
La familia TCP/IP nos ofrece dos protocolos de nivel de transporte TCP y UDP. La
diferencia fundamental es que mientras TCP es un servicio orientado a la conexin
(connection-oriented, stream service), y UDP no lo es. Por tanto en TCP, un proceso
que desea comunicarse con otro debe establecer una conexin y una vez terminada
la comunicacin debe romper esa conexin.
TCP acepta mensajes de longitud arbitrariamente grandes, que deber separar en
pedazos (segmentacin) que no excedan de los 64Kbytes (mximo aceptado por IP),
envindolos como mensajes separados. Como IP no garantiza el orden de los
mensajes, es trabajo de TCP reensamblar de forma correcta los submensajes antes
de entregar el mensaje completo y libre de errores al destinatario.
Adems utiliza nmeros de 16 bits para identificar varios destinos dentro de una
misma mquina. Son los llamados puertos". Un proceso que quiera contactar con otro
de una mquina remota debe conocer adems de la direccin Internet de la otra
mquina, el nmero de puerto en el que el otro proceso est escuchando.
Un servicio UDP por otro lado, ofrece en esencia lo mismo que el protocolo IP de nivel
3, con dos diferencias fundamentales:
1. Ofrece la posibilidad de deteccin de errores (pero se puede perder un
mensaje entero y UDP no nos avisar).
2. Al igual que TCP, gestiona nmeros de puerto permitiendo varias
comunicaciones simultneas en una misma mquina.
2. SOCKETS EN C
2.1. Conceptos bsicos.
Los sockets son una de las herramientas que ofrecen los Sistemas Operativos para la
comunicacin entre diferentes procesos. La particularidad que tienen frente a otros
mecanismos de comunicacin entre procesos (IPC Inter-Process Communication)
es que posibilitan la comunicacin an cuando ambos procesos estn corriendo en
distintos sistemas unidos mediante una red. De hecho, el API de sockets es la base
de cualquier aplicacin que funcione en red puesto que ofrece una librera de
funciones bsicas que el programador puede usar para desarrollar aplicaciones en
red.
Laboratorio de Arquitectura de Redes
- 5 -
Este API permite la comunicacin sobre una gran variedad de redes, pero en este
manual nos concentraremos en su uso sobre redes TCP/IP.
Los sockets para TCP/IP permiten la comunicacin de dos procesos que estn
conectados a travs de una red TCP/IP. En una red de este tipo, cada mquina est
identificada por medio de su direccin IP que debe ser nica. Sin embargo, en cada
mquina pueden estar ejecutndose mltiples procesos simultneamente. Cada uno
de estos procesos se asocia con un nmero de puerto, para poder as diferenciar los
distintos paquetes que reciba la mquina (proceso de multiplexacin).
Un socket se identifica unvocamente por la dupla direccin IP + nmero de puerto.
Una comunicacin entre dos procesos se identifica mediante la asociacin de los
sockets que estos emplean para enviar y recibir informacin hacia y desde la red:
identificador de socket origen + identificador de socket destino.
Figura 2-1: Comunicacin entre aplicaciones en una red TCP/IP
Un socket es una abstraccin a travs de la cual una aplicacin puede enviar y recibir
informacin de manera muy similar a como se escribe y lee de un fichero. La
informacin que una aplicacin enva por su socket origen puede ser recibida por otra
aplicacin en el socket destino y viceversa.
Existen diferentes tipos de sockets dependiendo de la pila de protocolos sobre la que
se cree dicho socket. Nos centraremos en la pila de protocolos TCP/IP.
Laboratorio de Arquitectura de Redes
- 6 -
Figura 2-2: Interfaz de sockets
En este manual se ver como se le pueden asociar estos parmetros a los sockets
creados.
Figura 2-3: Sockets, protocolos y puertos
La Figura 2-3 muestra la relacin lgica entre aplicaciones, sockets, protocolos y
puertos en un dispositivo. Hay varios aspectos a destacar en esta relacin. Primero, un
programa puede usar ms de un socket al mismo tiempo. Segundo, diferentes
programas pueden usar el mismo socket al mismo tiempo aunque esto es menos
comn. Como se muestra en la Figura 2-3, cada socket tiene asociado un puerto TCP
o UDP, segn sea el caso. Cuando se recibe un paquete dirigido a dicho puerto, este
paquete se pasa a la aplicacin correspondiente.
2.2 Domini os de comuni cacin.
Los sockets se crean dentro de lo que se denomina un dominio de comunicacin, al
igual que un archivo se crea dentro de un sistema de ficheros concreto. El dominio de
comunicacin permite definir el lugar donde se encuentran los procesos que se van
comunicar.
Laboratorio de Arquitectura de Redes
- 7 -
Los dominios que se definen en el lenguaje C son los siguientes:
AF_UNIX: representa el dominio caracterstico de los procesos que se
comunican dentro en un mismo sistema UNIX.
AF_INET: es el dominio que utilizan los procesos que se comunican a travs
de cualquier red TCP/IP.
Alguno ms que no vamos a estudiar.
Destacar que en esta introduccin nicamente se har referencia a sockets creados
bajo el dominio AF_INET.
2.3 Ti pos de sockets.
En el dominio AF_INET se definen los siguientes tipos de sockets:
Sockets Stream
Sockets Datagram
Sockets Raw
El tipo de sockets Stream hace uso del protocolo TCP (protocolo de la capa de
transporte) que provee un flujo de datos bidireccional, orientado a conexin,
secuenciado, sin duplicacin de paquetes y libre de errores.
El tipo de sockets Datagram hacen uso del protocolo UDP (protocolo de la capa de
transporte), el cual provee un flujo de datos bidireccional, no orientado a conexin, en
el cual los paquetes pueden llegar fuera de secuencia, puede haber prdidas de
paquetes o pueden llegar con errores.
El tipo de sockets Raw permiten un acceso a ms bajo nivel, pudiendo acceder
directamente al protocolo IP del nivel de Red. Su uso est mucho ms limitado ya que
est pensado principalmente para desarrollar nuevos protocolos de comunicacin, o
para obviar los protocolos del nivel de transporte.
2.4 Ordenacin de los bytes.
Los microprocesadores que incorporan los ordenadores poseen dos formas diferentes
de representar los nmeros, primero el byte ms significativo y luego el menos
significativo (Big-Endian) o al revs (Little-Endian).
Esta diferencia, que dentro de un microprocesador no deja de ser una ancdota,
adquiere su importancia en el mundo de las redes, pues si cada ordenador manda los
datos como los representa internamente (Big-Endian o Little-Endian), el ordenador que
recibe dichos datos puede interpretarlos correctamente o incorrectamente,
dependiendo de si su formato de representacin coincide con el del emisor o no.
Por ejemplo, si un ordenador indica que desea establecer una conexin con el puerto
80 (servidor Web) de otro ordenador, si lo enva en formato Big-Endian los bytes que
enviar sern: 0x00 0x50, mientras que en formato Little-Endian enviar los bytes
0x50 0x00. Si el otro ordenador representa los datos en formato diferente, al recibir,
por ejemplo, 0x00 0x50 lo traducir como el puerto 0x50 0x00, esto es 20480, que
obviamente no corresponde al servidor Web.
Laboratorio de Arquitectura de Redes
- 8 -
Para solventar este problema, se defini un formato conocido como Orden de los
Bytes en la Red (Network Byte Order), que establece un formato comn para los datos
que se envan por la red, como son el nmero de puerto, etc., de forma que todos los
datos, antes de ser enviados a las funciones que manejan las conexiones en la red,
deben ser convertidos a este formato de red. A continuacin, podemos ver las cuatro
funciones que permiten manejar estos datos.
htonl.
#i ncl ude <net i net / i n. h>
unsi gned l ong i nt ht onl ( unsi gned l ong i nt host l ong) ;
La funcin htonl convierte el entero de 32 bits dado por hostlong desde el orden de
bytes del hosts al orden de bytes de la red.
Ejemplo:
unsi gned l ong i nt r ed, host ;
. . .
r ed=ht onl ( host ) ;
htons.
#i ncl ude <net i net / i n. h>
unsi gned shor t i nt ht ons( unsi gned shor t i nt host shor t ) ;
La funcin htons convierte el entero de 16 bits dado por hostshort desde el orden de
bytes del hosts al orden de bytes de la red.
Ejemplo:
unsi gned shor t i nt r ed, host ;
. . .
r ed=ht ons( host ) ;
ntohl.
#i ncl ude <net i net / i n. h>
unsi gned l ong i nt nt ohl ( unsi gned l ong i nt net l ong) ;
La funcin ntohl convierte el entero de 32 bits dado por netlong desde el orden de
bytes de la red al orden de bytes del hosts.
Ejemplo:
unsi gned l ong i nt host , r ed;
. . .
host =nt ohl ( r ed) ;
ntohs.
#i ncl ude <net i net / i n. h>
unsi gned shor t i nt nt ohs( unsi gned shor t i nt net shor t ) ;
La funcin ntohs convierte el entero de 16 bits dado por netshort desde el orden de
bytes de la red al orden de bytes del hosts.
Ejemplo:
unsi gned shor t i nt host , r ed;
. . .
host =nt ohs( r ed) ;
Laboratorio de Arquitectura de Redes
- 9 -
2.5 Servici o ori entado a conexin (TCP)
2.5.1 El modelo utilizado
El modelo ms utilizado para el desarrollo de aplicaciones en red es el de cliente-
servidor. Un servidor es un proceso que espera contactar con algn proceso cliente
para darle algn tipo de servicio. Un proceso de comunicacin tpico siguiendo este
modelo es el siguiente:
1. El proceso servidor se pone en ejecucin en algn computador. Inicializa sus
estructuras de datos y se queda esperando a que algn cliente requiera sus
servicios.
2. Un proceso es puesto en ejecucin en el mismo computador o en otro de la
red. En algn momento este proceso necesita acceder al servidor, se convierte
en este momento en proceso cliente, enviando una peticin de servicio a travs
de la red y se queda esperando respuesta.
3. El servidor despierta, atiende la peticin, responde a su cliente actual y se
queda de nuevo esperando otro cliente.
A continuacin se describen los pasos a realizar para la creacin de un servicio
orientado a conexin (TCP), tanto en la parte cliente como en la parte del servidor. En
la siguiente figura se muestran los pasos a realizar en ambos casos, invocando
diversas funciones, cuyo funcionamiento ser detallado a continuacin.
Figura 2-4 Llamadas al sistema para sockets en un protocolo orientado a la conexin
El servidor crear inicialmente un extremo de la conexin pidiendo un socket
(socket ( ) ) y dndole una direccin local (bi nd( ) ). El servidor puede en algn
momento recibir varias peticiones de conexin simultneas por lo que se ofrece una
llamada que permite especificar el nmero mximo de conexiones pendientes
(l i st en( ) ). Despus queda esperando la peticin de conexin por parte de algn
cliente (accept ( ) ).
Laboratorio de Arquitectura de Redes
- 10 -
Por otro lado el cliente crear un socket, le dar una direccin local y lanzar una
peticin de conexin al servidor (connect ( ) ). Si el servidor est disponible (ha
ejecutado accept y no hay peticiones anteriores encoladas) inmediatamente se
desbloquean tanto cliente como servidor. En la parte del servidor se habr creado un
nuevo socket (cuyo identificador devuelve accept ( ) ) que es el que realmente est
conectado con el cliente, de forma que el original sigue sirviendo al servidor para
atender nuevas peticiones de conexin.
Cliente y servidor se intercambiarn datos mediante r ead( ) y wr i t e( ) (tambin se
utilizan las funciones send( ) y r ecv( ) para realizar la transferencia de datos),
pudiendo finalmente cerrar la conexin mediante la llamada cl ose( ) .
2.5.2 Resumen de ll amadas al sistema.
a) Creacin de socket.
Para crear un socket se usa la llamada al sistema socket ( ) especificando la familia de
protocolos que usar y el tipo de conexin. La funcin devuelve un entero que
llamaremos descriptor de socket y servir para referenciar al socket en el resto de las
llamadas (al igual que el file descriptor en el acceso a ficheros).
b) Asignaci n de direcci n local
La llamada socket ( ) no asigna una direccin al socket creado. Automticamente las
llamadas send( ) y connect ( ) asignan a nuestro socket la direccin IP de nuestra
mquina y un nmero de puerto libre. Sin embargo hay casos en que necesitaremos
dar una direccin determinada a un socket.
Todos los clientes deben conocer la direccin de su servidor para poder pedirle
servicios, para ello el servidor crear un socket con una direccin IP y un puerto que
har pblicos. Para asignar una direccin determinada a un socket se usa la
llamada bi nd( ) .
c) La llamada al sistema listen()
Una vez realizada la llamada l i st en( ) , todas las peticiones de conexin que lleguen
al socket sern guardadas en su cola de peticiones. A continuacin el proceso
propietario del socket podr atender la primera de ellas mediante la llamada accept ( ) .
d) La llamada al sistema accept()
Si al realizar esta llamada la cola de peticiones estaba vaca el proceso quedar
bloqueado hasta la llegada de una nueva peticin. Una vez ha llegado una peticin el
sistema crea un nuevo socket cuyo descriptor devuelve la llamada accept ( ) , y que
ser el utilizado en la comunicacin.
e) Estableciendo conexin.
La llamada connect ( ) sirve al cliente para realizar una peticin de conexin al
servidor. Esta peticin ser inmediatamente atendida si el servidor estaba bloqueado
en accept ( ) , o ser encolada si la cola no estaba vaca o el servidor no acepta
conexin en ese momento.
Laboratorio de Arquitectura de Redes
- 11 -
f) Transferencia de datos.
Cuando dos procesos ya han quedado "enganchados" por una conexin, pueden
enviar-recibir datos, para ello se usan las llamadas send( ) y r ecv( ) . Estas llamadas
slo trabajan con sockets "conectados" ya que no permiten especificar direccin
destino.
g) Cerrar la conexin
Cuando hagamos cl ose( ) , el sistema nos asegurar que antes de destruir el socket
todos los datos que han sido enviados sern recibidos en el otro extremo.
2.6. Creacin de un socket
Los sockets se crean llamando a la funcin socket ( ) , que devuelve el identificador de
socket, de tipo entero (es equivalente al concepto de identificador de fichero).
En caso de que se haya producido algn error durante la creacin del socket, la
funcin devuelve -1 y la variable global er r no se establece con un valor que indica el
error que se ha producido. La funcin per r or ( . . . ) muestra por pantalla un
mensaje explicativo sobre el error que ha ocurrido.
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
i nt socket( i nt domai n, i nt t ype, i nt pr ot ocol ) ;
ht t p: / / l i nux. di e. net / man/ 2/ socket
El prototipo de la funcin socket ( ) es el siguiente:
sockf d = socket ( i nt domi ni o, i nt t i po, i nt pr ot ocol o ) ;
sockf d: Identificador de socket. Se utilizar para conectarse, recibir
conexiones, enviar y recibir datos, etc.
domi ni o: Dominio donde se realiza la conexin. En este caso, el dominio
ser siempre AF_I NET.
t i po: Se corresponde con el tipo de socket que se va a crear, y puede
tomar los siguientes valores (definidos como constantes en las libreras):
SOCK_STREAM, SOCK_DGRAM o SOCK_RAW.
pr ot ocol o: Indica el protocolo que se va a utilizar. El valor 0 indica que
seleccione el protocolo ms apropiado (TCP para SOCK_STREAM, UDP para
SOCK_DGRAM).
A continuacin se muestra un ejemplo de utilizacin:
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
. . .
i nt sockf d;
sockf d = socket ( AF_I NET, SOCK_STREAM, 0 ) ;
. . .
Laboratorio de Arquitectura de Redes
- 12 -
2.6.1 Estructuras de datos
La funcin socket ( ) nicamente crea un socket, pero no le asigna ningn valor, esto
es, no lo asocia a ninguna direccin IP ni a ningn puerto.
Para poder realizar esta asociacin, lo primero es conocer una serie de estructuras
que son necesarias para llevarla a cabo.
st r uct sockaddr
{
unsi gned shor t sa_f ami l y; / / AF_*
char sa_dat a[ 14] ; / / Di r ecci n de pr ot ocol o.
};
st r uct sockaddr_in
{
shor t i nt si n_f ami l y; / / AF_I NET
unsi gned shor t si n_por t ; / / Numer o de puer t o.
st r uct i n_addr si n_addr ; / / Di r ecci n I P.
unsi gned char si n_zer o[ 8] ; / / Rel l eno.
};
st r uct in_addr
{
unsi gned l ong s_addr ; / / 4 byt es.
};
La estructura sockaddr es la estructura genrica que se usa en las diferentes
funciones definidas en el API de Sockets. Como puede comprobarse, slo define el
dominio mientras que los datos (los parmetros del socket) quedan sin especificar
(simplemente se reserva espacio en memoria, pero sin ninguna estructura especfica).
Esto permite que esta estructura pueda emplearse en cualquiera que sea el dominio
con el que se haya definido el socket.
Para poder definir los parmetros que se quieren asociar al socket, se usan
estructuras especficas para cada dominio. La estructura TCP/IP es la sockaddr _i n,
equivalente a la estructura sockaddr , pero que permite referenciar a sus elementos
de forma ms sencilla.
Los campos de la estructura sockaddr _i n son los siguientes:
sin_family: Tomar siempre el valor AF_I NET.
sin_port: Representa el nmero de puerto, y debe estar en la ordenacin
de bytes de la red.
sin_zero: Se utiliza simplemente de relleno para completar la longitud de
sockaddr.
sin_addr: Este campo representa la direccin IP y se almacena en un
formato especfico, que se detalla a continuacin.
Para convertir una direccin IP en formato texto (por ejemplo, 193.144.57.67) a un
unsi gned l ong con la ordenacin de bytes adecuada, se utiliza la funcin
i net _addr ( ) . Esta funcin convierte nicamente direcciones IP a formato numrico,
NO convierte nombres de mquinas. En caso de error devuelve 1 y activa la variable
global er r no.
Laboratorio de Arquitectura de Redes
- 13 -
2.6.2 Asociaci n de un socket a unos parmetros determi nados
La funcin bi nd( ) se utiliza para asociar el socket a estos parmetros, mediante una
direccin IP y nmero de puerto de la mquina local, a travs de los que se enviarn y
recibirn datos.
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
i nt bind( i nt sockf d, st r uct sockaddr *my_addr , i nt addr l en) ;
ht t p: / / l i nux. di e. net / man/ 2/ bi nd
El prototipo de la funcin es el siguiente:
i nt bind( i nt sockf d, st r uct sockaddr *my_addr , i nt addr l en) ;
sockf d: Identificador de socket devuelto por la funcin socket ( ) .
my_addr : Es un puntero a una estructura sockaddr que contiene la IP de
la mquina local y el nmero de puerto que se va a asignar al socket (esta
estructura se detalla en la siguiente seccin).
addr l en: debe estar establecido al tamao de la estructura anterior,
utilizando para ello la funcin sizeof().
Ejemplo:
bind ( sockf d, ( st r uct sockaddr *) &si n, si zeof ( si n) ) ;
Previamente a la llamada a la funcin bi nd( ) es necesario asignar valores a una
variable de tipo sockaddr _i n que sern los parmetros que se asociarn al socket.
Ejemplo:
...
st r uct sockaddr _i n si n;
...
si n. si n_f ami l y = AF_I NET;
si n. si n por t = ht ons ( 1234 ) ;
/ / Nmer o de puer t o donde r eci bi r paquet es el pr ogr ama
si n. si n_addr . s_addr = i net _addr ( "132. 241. 5. 10" ) ;
/ / I P por l a que r eci bi r paquet es el pr ogr ama
...
Existen algunos casos especiales a la hora de asignar valores a ciertos
campos:
En caso de asignar el valor cero a si n_por t , el sistema fijar el nmero de
puerto al primero que encuentre disponible.
Para realizar la asignacin de la direccin IP de forma automtica (sin tener
por que conocer previamente la direccin IP donde se va a ejecutar el
programa) se puede utilizar la constante: I NADDR_ANY. Esto le indica al
sistema que el programa recibir mensajes por cualquier IP vlida de la
mquina, en caso de disponer de varias.
Laboratorio de Arquitectura de Redes
- 14 -
Ejemplo:
. . .
si n. si n_por t = 0;
si n. si n_addr . s_addr = ht onl ( I NADDR_ANY) ;
. . .
2.6.3 Habili tar un socket para recibi r peti ciones de conexin
#i ncl ude <sys/ socket . h>
i nt listen( i nt sockf d, i nt backl og) ;
ht t p: / / l i nux. di e. net / man/ 2/ l i st en
El primer paso para la comunicacin usando un servicio orientado a la conexin
(protocolo de transporte TCP) es el establecimiento de una conexin TCP. En este
sentido, an cuando se haya creado un socket de tipo SOCK_STREAM, el socket no est
preparado para establecer dicha conexin.
Para habilitar un socket para recibir peticiones de conexin y proceder al
establecimiento de dicha conexin, es necesario utilizar la funcin l i st en( ) .
La funcin l i st en( ) se invoca nicamente desde el servidor, y habilita al socket para
poder recibir conexiones. nicamente se aplica a sockets de tipo SOCK_STREAM.
El prototipo de la funcin es el siguiente:
i nt listen ( i nt sockf d, i nt backl og) ;
sockf d: Identificador de socket obtenido en la funcin socket ( ) , que ser
utilizado para recibir conexiones.
backl og: Nmero mximo de conexiones en la cola de entrada de conexiones.
Las conexiones entrantes quedan en estado de espera en esta cola hasta que
sean aceptadas mediante la funcin accept ( ) .
2.6.4 Aceptar petici ones de conexin
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
i nt accept( i nt sockf d, st r uct sockaddr *addr , sockl en_t
*addr l en) ;
ht t p: / / l i nux. di e. net / man/ 2/ accept
Laboratorio de Arquitectura de Redes
- 15 -
Si bien la funcin l i st en() prepara el socket y lo habilita para recibir peticiones de
establecimiento de conexin, es la funcin accept () la que realmente queda a la
espera de estas peticiones. Cuando una peticin realizada desde un proceso remoto
(cliente) es recibida, la conexin se completa en el servidor siempre y cuando ste
est esperando en la funcin accept ().
La funcin accept () es utilizada en el servidor una vez que se ha invocado a la funcin
l i st en(). Esta funcin espera hasta que algn cliente establezca una conexin con el
servidor. Es una llamada bloqueante, esto es, la funcin no finalizar hasta que se
haya producido una conexin o sea interrumpida por una seal.
Es conveniente destacar que una vez que se ha producido la conexin, la funcin
accept () devuelve un nuevo identificador de socket que ser utilizado para la
comunicacin con el cliente que se ha conectado.
El prototipo de la funcin es el siguiente:
i nt accept ( i nt sockf d, st r uct sockaddr *addr , sockl en_t
*addr l en) ;
sockf d: Identificador de socket habilitado para recibir conexiones.
addr : Puntero a una estructura sockaddr (en nuestro caso su equivalente
sockadd_i n), donde se almacenar la informacin (direccin IP y nmero de
puerto) del proceso que ha realizado la conexin.
addr l en: Debe contener un puntero a un valor entero que represente el
tamao la estructura addr . Debe ser establecido al tamao de la estructura
sockaddr , mediante la llamada si zeof ( st r uct sockaddr ) . Si la funcin
escribe un nmero de bytes menor, el valor de addr l en es modificado a la
cantidad de bytes escritos.
Ejemplo:
. . .
i nt sockf d, new_sockf d;
st r uct sockaddr _i n ser ver _addr ;
st r uct sockaddr _i n r emot e_addr ;
i nt addr l en;
/ / Cr eaci n del socket .
sockf d = socket ( PF_I NET, SOCK_STREAM, 0 ) ;
/ / Def i ni r val or es en l a est r uct ur a ser ver _addr .
si n. si n_f ami l y = AF_I NET;
si n. si n por t = ht ons ( 1234 ) ; / / Nmer o de puer t o donde
/ / r eci bi r paquet es el pr ogr ama
si n. si n_addr . s_addr = ht onl ( I NADDR_ANY) ;
/ / Asoci ar val or es def i ni dos al socket
bi nd( sockf d, ( st r uct sockaddr *) &ser ver _addr , si zeof ( st r uct
sockaddr ) ) ;
/ / Se habi l i t a el socket par a poder r eci bi r conexi ones.
Laboratorio de Arquitectura de Redes
- 16 -
l i st en ( sockf d, 5) ;
addr l en = si zeof ( st r uct sockaddr ) ;
/ / Se l l ama a accept ( ) y el ser vi dor queda en esper a de
conexi ones.
new_sockf d = accept ( sockf d, &r emot e_addr , &addr l en) ;
. . .
2.6.5. Lanzar peti ciones de conexin
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
i nt connect( i nt sockf d, const st r uct sockaddr *ser v_addr ,
sockl en_t addr l en) ;
ht t p: / / l i nux. di e. net / man/ 2/ connect
Esta funcin es invocada desde el cliente para solicitar el establecimiento de una
conexin TCP.
La funcin connect () inicia la conexin con el servidor remoto, por parte del cliente. El
prototipo de la funcin es el siguiente:
i nt connect ( i nt sockf d, st r uct sockaddr *ser v_addr , i nt
addr l en) ;
sockf d: Identificador de socket devuelto por la funcin socket ( ) .
ser v_addr : Estructura sockaddr que contiene la direccin IP y nmero de
puerto del destino.
addr l en: Debe ser inicializado al tamao de la estructura ser v_addr ,
pasada como parmetro.
Ejemplo:
. . .
i nt sockf d;
st r uct sockaddr _i n r emot e_addr ;
i nt addr l en;
/ / Cr eaci n del socket .
sockf d = socket ( AF_I NET, SOCK_STREAM, 0 ) ;
/ / Def i ni r val or es en l a est r uct ur a ser ver _addr .
si n. si n_f ami l y = AF_I NET;
si n. si n por t = ht ons ( 1234 ) ; / / Nmer o de puer t o donde
/ / est esper ando el ser vi dor
si n. si n_addr . s_addr = i net _addr ( 1. 2. 3. 4) ; / / Di r ecci n I P
/ / del ser vi dor
addr l en = si zeof ( st r uct sockaddr ) ;
Laboratorio de Arquitectura de Redes
- 17 -
/ / Se l l ama a connect ( ) y se hace l a pet i ci n de conexi n
al ser vi dor
connect ( sockf d, &r emot e_addr , &addr l en) ;
. . .
2.6.6 Conexin entre l os sockets del cl iente y servi dor
Una vez que el cliente ha hecho la llamada a la funcin connect () y esta ha concluido
con xito (lo que significa que el servidor estaba esperando en la funcin accept () y
al salir ha creado el nuevo socket), la situacin es la que se muestra en la siguiente
figura.
Figura 2-5 Sockets, protocolos y puertos
Como se puede apreciar en la figura, se crea una conexin entre el socket usado por
el cliente en la funcin connect () (sockf d en nuestro ejemplo) y el socket que
devuelve la funcin accept () en el servidor (new_sockf d en nuestro ejemplo).
Esta conexin permitir la comunicacin entre ambos procesos usando los sockets
que estn conectados
2.6.7 Enviar y recibi r datos a travs de un socket TCP
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
ssi ze_t send( i nt s, const voi d *buf , si ze_t l en, i nt
f l ags) ;
ht t p: / / l i nux. di e. net / man/ 2/ send
.......................................................................
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
ssi ze_t recv( i nt s, voi d *buf , si ze_t l en, i nt f l ags) ;
ht t p: / / l i nux. di e. net / man/ 2/ r ecv
Laboratorio de Arquitectura de Redes
- 18 -
Una vez que la conexin ha sido establecida, se inicia el intercambio de datos,
utilizando para ello las funciones send() yr ecv().
El prototipo de la funcin send() es el siguiente:
ssi ze_t send ( i nt sockf d, const voi d *buf , si ze_t l en, i nt
f l ags ) ;
sockf d: Identificador de socket para enviar datos.
buf : Puntero a los datos que sern enviados.
l en: Nmero de bytes a enviar.
f l ags: Por defecto, 0.
La funcin send( ) devuelve el nmero de bytes enviados, que puede ser menor que
la cantidad indicada en el parmetro l en.
La funcin r ecv( ) se utiliza para recibir datos, y posee un prototipo similar a la
anterior:
ssi ze_t recv ( i nt sockf d, voi d *buf , si ze_t l en, i nt
f l ags) ;
sockf d: Identificador de socket para la recepcin de los datos.
buf : Puntero a un buffer donde se almacenarn los datos recibidos.
l en: Nmero mximo de bytes a recibir
f l ags: Por defecto, 0. Para ms informacin, consultar la ayuda en lnea.
La funcin r ecv() es bloqueante, no finalizando hasta que se ha recibido algn tipo de
informacin. Resaltar que el campo l en indica el nmero mximo de bytes a recibir,
pero no necesariamente se han de recibir exactamente ese nmero de bytes. La
funcin r ecv() devuelve el nmero de bytes que se han recibido.
Ejemplo:
char mens_ser v[ 100] ;
. . .
mens_cl i en = Ej empl o;
send( si d, mens_cl i en, st r l en( mens_cl i en) +1, 0) ;
. . .
r ecv( si d, mens_ser v, 100, 0) ;
. . .
2.6.8 Cierre de un socket
#i ncl ude <uni st d. h>
i nt close( i nt f d) ;
ht t p: / / l i nux. di e. net / man/ 2/ cl ose
Simplemente hay que hacer la llamada a la funcin pasndole como argumento el
descriptor del socket que se quiere cerrar.
Laboratorio de Arquitectura de Redes
- 19 -
Es importante que cuando un socket no vaya a usarse ms, se haga la llamada a
cl ose() para indicrselo al Sistema Operativo y que ste lo libere.
Si se desea un poco ms de control sobre cmo se cierra el socket se puede usar la
funcin shut down( ) que permite cortar la comunicacin en un sentido, o en los dos
(como lo hace cl ose( ) ) .
#i ncl ude <sys/ socket . h>
i nt shutdown( i nt sockf d, i nt how)
ht t p: / / l i nux. di e. net / man/ 2/ shut down
sockf d es el descriptor de socket que se desea desconectar, y how puede tener uno
de los siguientes valores:
0 -- No se permite recibir ms datos
1 -- No se permite enviar ms datos
2 -- No se permite enviar ni recibir ms datos (similar a cl ose())
shut down() devuelve 0 si tiene xito, y -1 en caso de error.
Si se usa shut down() en un datagram socket, simplemente inhabilitar el socket para
posteriores llamadas a send() yr ecv()
shut down() no cierra realmente el descriptor de fichero, slo cambia sus condiciones
de uso. Para liberar un descriptor de socket es necesario usar cl ose().
Laboratorio de Arquitectura de Redes
- 20 -
2.7 Di agrama de estados de una conexin TCP
En la siguiente figura se muestran los estados por los que puede pasar una conexin
TCP. Asimismo, se detallan los eventos y los segmentos que se intercambian en cada
transicin de un estado a otro.
Figura 2-6: Diagrama de estados de una conexin TCP
Tal y como se puede comprobar, un socket al crearse est en el estado CLOSED.
Existen dos posibilidades para salir de este estado, una apertura activa o una apertura
pasiva. Mientras que la primera se da en el cliente cuando este realiza la llamada a la
funcin connect () y con ella inicia el proceso de establecimiento de la conexin, la
segunda ocurre en el servidor una vez hechas las llamadas a las funciones
l i st en( ) y accept (). De esta forma, en el servidor el socket utilizado para recibir
peticiones de establecimiento de conexin pasa al estado LI STEN, y espera a que
desde el cliente se inicie el proceso de establecimiento de la conexin.
Tras el establecimiento de la conexin, tanto el socket creado en el cliente como el
socket que devuelve la funcin accept () pasan al estado ESTABLI SHED. El socket
utilizado por el servidor para recibir peticiones de establecimiento de conexin
contina en el estado LI STEN.
El intercambio de datos tiene lugar entre los sockets que estn en el estado
ESTABLI SHED. Una vez finalizado ste, ambos sockets pasan al estado CLOSED (tras
Laboratorio de Arquitectura de Redes
- 21 -
atravesar una serie de estados intermedios). El evento que provoca este cierre es la
llamada en ambos procesos (cliente y servidor) a la funcin cl ose().
2.8 Servicio no orientado a conexin (UDP)
2.8.1 El modelo utilizado
Las llamadas ofrecidas para la comunicacin sin conexin son ms sencillas que las
vistas anteriormente. Su esquema de funcionamiento se detalla a continuacin:
Figura 2-7 Llamadas al sistema para sockets en un protocolo no orientado a la conexin
En primer lugar el servidor crea un socket (llamada socket ()). En la creacin, al
socket no se le asigna nombre (direccin local) por lo que el resto de procesos no
pueden referenciarlo, y por lo tanto no se pueden recibir mensajes en l.
Mediante la llamada bi nd() se asigna una direccin local al socket (para TCP/IP una
direccin local es la direccin IP de la mquina ms un nmero de port). Esta direccin
deber ser conocida por los clientes. Una vez configurado el socket, el servidor puede
quedar esperando la recepcin de un mensaje utilizando la llamada r ecvf r om().
Por otro lado el cliente deber igualmente crear un socket y asignarle una direccin de
su mquina. Una vez hecho esto podr enviar mensajes (peticiones de servicio) al
servidor usando la llamada sendt o() en la que especificar como direccin destino la
del socket creado por el servidor.
La llamada r ecvf r om() proporcionar al servidor la direccin del cliente, que podr
ser usada por el primero para enviar la respuesta. Pudiendo finalmente cerrar la
conexin mediante la llamada cl ose().
Laboratorio de Arquitectura de Redes
- 22 -
2.8.2 Enviar y recibi r datos a travs de un socket UDP
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
ssi ze_t sendto( i nt s, const voi d *buf , si ze_t l en, i nt f l ags,
const st r uct sockaddr *t o, sockl en_t t ol en) ;
ht t p: / / l i nux. di e. net / man/ 2/ send
.......................................................................
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
ssi ze_t recvfrom( i nt s, voi d *buf , si ze_t l en, i nt f l ags,
st r uct sockaddr *f r om, sockl en_t *f r oml en) ;
ht t p: / / l i nux. di e. net / man/ 2/ r ecv
En el caso de envo y recepcin de datos a travs de sockets no orientados a la
conexin, se utilizan estas funciones pues es necesario indicar quien es el destinatario
u origen de los datos enviados o recibidos.
El prototipo de la funcin sendt o() es el siguiente:
ssi ze_t sendto( i nt sockf d, const voi d *buf , si ze_t l en, i nt
f l ags, const st r uct sockaddr *t o, sockl en_t t ol en) ;
sockf d: Identificador de socket para el envo de datos.
buf : Puntero a los datos a ser enviados.
l en: Longitud de los datos en bytes.
f l ags: Por defecto, 0.
t o: Puntero a una estructura sockaddr que contiene la direccin IP y nmero
de puerto destino.
tolen: Debe ser inicializado al tamao de st r uct sockaddr , mediante la
funcin si zeof ().
La funcin sendt o() devuelve el nmero de bytes enviados, que puede ser menor que
el valor indicado enl en.
Es importante destacar que al no existir ninguna conexin, cuando se envan datos a
travs de un socket UDP, es necesario indicar cual debe ser el socket remoto. En la
estructura t o, que en nuestro caso ser una estructura sockaddr _i n, deber estar
contenida esta informacin.
El prototipo de la funcin r ecvf r om() es el siguiente:
ssi ze_t recvfrom ( i nt sockf d, voi d *buf , si ze_t l en, i nt
f l ags, st r uct sockaddr *f r om, sockl en_t *f r oml en) ;
Laboratorio de Arquitectura de Redes
- 23 -
sockf d: Identificador de socket para la recepcin de datos.
buf : Puntero al buffer donde se almacenarn los datos recibidos.
l en: Nmero mximo de bytes a recibir.
f l ags: Por defecto, 0.
f r om: Puntero a una estructura sockaddr (vaca) donde se rellenarn la
direccin IP y nmero de puerto del proceso que enva los datos.
f r oml en: Debe ser inicializado al tamao de la estructura from, utilizando la
funcin sizeof().
El campo f r oml en debe contener un puntero a un valor entero que represente el
tamao la estructura f r om.
La llamada a la funcin r ecvf r om() es bloqueante, no devolviendo el control hasta
que se han recibido datos. Al finalizar devuelve el nmero de bytes recibidos.
Es importante destacar, que adems de recibir los datos y almacenarlos a partir de la
posicin de memoria a la que apunta buf , la llamada a r ecvf r om() permite conocer
los parmetros que identifican al socket que envo estos datos. Estos parmetros se
almacenan en una estructura sockaddr (en nuestro caso sockaddr _i n) para lo cual
es necesario que en la llamada le pasemos como parmetro la estructura, vaca,
donde queremos que se almacenen.
Esta es la razn por la que antes de realizar una llamada a sendt o() en el servidor se
haga la llamada a r ecvf r om(). Mientras que el cliente conoce a priori los detalles del
socket del servidor, y por tanto podr rellenar los campos de la estructura t o antes de
la llamada a la funcin sendt o(), el servidor no conoce estos datos del cliente (en
tanto en cuanto, este servidor puede servir a cualquier cliente en cualquier parte del
mundo). Por ello, debe esperar a recibir algo de forma que una vez se ejecute la
funcin r ecvf r om(), los detalles del socket utilizado por el cliente estn almacenados
en la estructura f r omy se puedan emplear para enviar la respuesta al cliente.
Ejemplo cliente:
. . .
st r uct sockaddr _i n sser v;
char mens_ser v[ 100] ;
mens_cl i en = Ej empl o;
. . .
/ / Pr evi ament e se ha r el l enado l a est r uct ur a sser v
/ / con l a di r ecci n I P y nmer o de puer t o del ser vi dor
sendt o( si d, mens_cl i en, st r l en( mens_cl i en) +1, 0, ( st r uct
sockaddr *) &sser v, si zeof ( sser v) ) ;
. . .
l ong = si zeof ( sser v) ;
r ecvf r om( si d, mens_ser v, 100, 0, ( st r uct sockaddr *) &
sser v, &l ong) ;
. . .
Laboratorio de Arquitectura de Redes
- 24 -
Ejemplo servidor:
. . .
st r uct sockaddr _i n sser v;
char mens_cl i [ 100] ;
. . .
l ong = si zeof ( sser v) ;
r ecvf r om( si d, mens_cl i , 100, 0, ( st r uct sockaddr *) &sser v,
&l ong) ;
/ / La est r uct ur a sser v ha si do r el l enada con l a di r ecci n
/ / I P y nmer o de puer t o del cl i ent e
. . .
sendt o( si d, mens_cl i en, st r l en( mens_cl i en) +1, 0, ( st r uct
sockaddr *) &sser v, si zeof ( sser v) ) ;
. . .
3. OTRAS FUNCIONALIDADES.
3.1 Funci n gethost name().
#i ncl ude <sys/ t ypes. h>
#i ncl ude <uni st d. h>
i nt gethostname( char *host name, si ze_t si ze)
ht t p: / / l i nux. di e. net / man/ 2/ get host name
La funcin get host name( ) devuelve el nombre del sistema donde se est ejecutando
el programa. devuelve 0 cuando se ha ejecutado con xito. El prototipo es el siguiente:
i nt gethostname ( char *host name, si ze_t si ze )
host name: Puntero a un array de caracteres donde se almacenar el nombre de
la mquina.
si ze: Longitud en bytes del array host name.
La funcin get host name( ) tambin se utiliza para convertir un nombre de mquina en
una direccin IP, a travs de una estructura de nombre host ent . El prototipo es el
siguiente:
st r uct host ent *gethostbyname ( const char *name)
name: Nombre de la mquina que se quiere convertir a direccin IP.
La funcin devuelve un puntero a una estructura host ent , que se define como sigue:
Laboratorio de Arquitectura de Redes
- 25 -
st r uct host ent
{
char *h_name;
char **h_al i ases;
i nt h_addr t ype;
i nt h_l engt h;
char **h_addr _l i st ;
};
#def i ne h_addr h_addr _l i st [ 0]
h_name: Nombre oficial de la mquina.
h_aliases: Array de nombres alternativos.
h_addrtype: Tipo de direccin de retorno ( AF_I NET ).
h_length: Longitud de la direccin en bytes.
h_addr_list: Array de direcciones de red para la mquina.
h_addr: La primera direccin en h_addr _l i st .
En el caso de producirse algn error, devuelve NULL y establece la variable h_er r no
con el cdigo de error.
3.2 Creaci n de un proceso hi jo. Funcin fork().
#i ncl ude <sys/ t ypes. h>
#i ncl ude <uni st d. h>
pi d_t fork( voi d) ;
ht t p: / / l i nux. di e. net / man/ 2/ f or k
La funcin f or k() permite crear un proceso dentro del proceso principal (o proceso
padre). El prototipo de la funcin f or k() es el siguiente:
pi d_t fork( voi d) ;
La funcin f or k() no recibe ningn parmetro. Al trmino de su ejecucin existirn dos
procesos idnticos cuya nica diferencia es el valor de la variable que devuelve la
funcin. Este valor es 0 para el nuevo proceso creado (proceso hijo) y para el proceso
principal (proceso padre) esa variable es un nmero mayor que 0 (corresponde con el
identificador de proceso del hijo). Si se produce un error, el valor de la variable ser -1.
Ejemplo:
pi d_t cpi d;
. . .
cpi d = f or k( ) ;
i f ( cpi d == - 1) { per r or ( " f or k") ; exi t ( EXI T_FAI LURE) ; }
i f ( cpi d > 0)
{ / / ode execut ed by par ent
pr i nt f ( " Chi l d PI D i s %l d\ n", cpi d) ;
Laboratorio de Arquitectura de Redes
- 26 -
. . .
}
el se { / / Code execut ed by chi l d
pr i nt f ( " My PI D i s %l d\ n" , ( l ong) get pi d( ) ) ;
. . .
}
. . .
El proceso hijo hereda todas las variables del proceso padre. Esta funcin se puede
utilizar para dotar de concurrencia a los servidores TCP.
3.3 Servi dores TCP concurrentes y secuencial es
Despus de realizada la conexin TCP, en el servidor se crea un socket que es el que
se emplea en la comunicacin con el cliente.
Si tras acabar de ofrecer el servicio a un cliente (sucesin de envos y respuestas
entre servidor y cliente), el servidor volviera a la funcin accept (), este podra aceptar
una nueva peticin de conexin por parte de otro cliente. Este modo de operacin se
denomina secuencial. Hasta que no he acabado de servir a un cliente no puedo
ofrecer servicio al siguiente.
Si por el contrario queremos que nuestro servidor sea concurrente, esto es, poder
servir a varios clientes al mismo tiempo. Debemos posibilitar que el servidor pueda
aceptar peticiones de conexin mientras se encuentra sirviendo a los clientes.
En principio esto es posible puesto que el socket que se emplea para aceptar
peticiones de conexin es distinto al socket que se usa para comunicarse con el
cliente. Sin embargo si slo se tiene un proceso, slo es posible volver a aceptar
peticiones una vez se ha completado el servicio al cliente.
Para poder llevarlo a cabo es necesario crear nuevos procesos cada vez que se
acepta un nuevo cliente. De esta forma, los hijos creados atendern a cada uno de los
clientes segn vayan llegando mientras el proceso padre vuelve a aceptar a nuevos
clientes y a crear nuevos hijos que los atiendan.
Figura 3-1: Conexiones en un servidor TCP concurrente
Laboratorio de Arquitectura de Redes
- 27 -
A continuacin se muestran los pasos a realizar, invocando diversas funciones, cuyo
funcionamiento ha sido detallado.
3.4 Servi dores UDP concurrentes y secuencial es
Al contrario que los servidores basados en sockets TCP, los servidores basados en
sockets UDP, tienen un nico socket que emplean para enviar y recibir informacin de
cualquier cliente.
Por ello, a priori cualquier servidor basado en un socket UDP puede ser concurrente
con un nico proceso puesto que simplemente tiene que responder (esto es hacer una
llamada a sendt o( ) ) inmediatamente despus de recibir los datos del cliente (a
travs de unr ecvf r om( ) ).
Laboratorio de Arquitectura de Redes
- 28 -
Sin embargo, existen servidores en los que debido a la propia lgica del servicio
prestado la concurrencia no es tan sencilla. Estos servicios son todos aquellos que
guarden el estado de los clientes. Pongamos como ejemplo un servicio que sea un
juego de azar. El estado de cada cliente ser el balance de ganancias o perdidas de
cada cliente. Si bien el servidor puede recibir la jugada del cliente, calcular si gana o
pierde y responder con el resultado, debe ser capaz de disociar a que cliente
corresponde cada una de las jugadas que recibe y modificar su estado de la manera
apropiada.
4. EJEMPLO.
4.1 Introduccin
En este ejemplo, el cliente nos pedir que introduzcamos un mensaje por teclado y se
lo enviar al servidor que nos lo mostrar por pantalla.
Se debe ejecutar el cliente y el servidor en hosts independientes (aunque dentro de un
mismo equipo se puede hacer desde dos ventanas de terminales distintas).
Iniciaremos en primer lugar el servidor, y se le deber asignar un puerto libre con
cualquier nmero entre 2000 y 65535. . Si el puerto est disponible, el servidor se
bloquear hasta que reciba una conexin desde el cliente (no tiene que hacer nada
hasta que se establezca una conexin).
Esta es una lnea de comandos tpica del servidor:
. / ser ver 55000
Para ejecutar el cliente se le tiene que pasar dos argumentos, el nombre del host en el
que el servidor est en ejecucin y el nmero de puerto en el que el servidor est
escuchando las conexiones Aqu est la lnea de comandos del cliente para conectar
con el servidor:
. / cl i ent nombr ehost 55000
Si ambos se estn ejecutando en el mismo equipo, para averiguar el nombre del host
basta con ejecutar el comando hostname en el servidor.
4.2 Descri pcin del programa Servidor.
Se pasa a describir las partes ms importantes del programa.
En primer lugar colocamos las libreras que contienen declaraciones utilizadas en la
mayora de programas que trabajan con sockets.
#i ncl ude <st di o. h>
#i ncl ude <st dl i b. h>
#i ncl ude <st r i ng. h>
#i ncl ude <uni st d. h>
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
#i ncl ude <net i net / i n. h>
A continuacin declaramos la siguiente funcin que se invoca cuando una llamada al
sistema falla. Se muestra un mensaje sobre el error y luego terminar el programa.
Laboratorio de Arquitectura de Redes
- 29 -
per r or . Ms informacin sobre la funcin al final (*)
voi d er r or ( const char *msg)
{
per r or ( msg) ;
exi t ( 1) ;
}
A continuacin declaramos la funcin principal y las variables principales.
i nt mai n ( i nt ar gc, char *ar gv[ ] )
{
i nt sockf d, newsockf d, por t no;
Donde sockf d y newsockf d son descriptores de fichero. Estas dos variables
almacenan los valores devueltos por la llamada al sistema socket. por t no almacena el
nmero de puerto en el que el servidor acepta conexiones.
El servidor lee los caracteres de la conexin socket en este buffer.
char buf f er [ 256] ;
A sockaddr _i n es una estructura que contiene una direccin de Internet.
st r uct sockaddr _i n ser v_addr , cl i _addr ;
Esta estructura se define ennet i net / i n. h (**)
La variable ser v_addr contendr la direccin del servidor, y cl i _addr contendr la
direccin del cliente que se conecta al servidor.
El usuario tiene que pasar el nmero de puerto en el que el servidor aceptar las
conexiones como argumento. Este cdigo muestra un mensaje de error si el usuario
no lo hace.
i f ( ar gc <2)
{
f pr i nt f ( st der r , "Er r or , no hay ni ngn puer t o") ;
exi t ( 1) ;
}
La llamada a socket ( ) crea un nuevo socket. Recibe tres argumentos. El primero es
el dominio, el segundo es el tipo de socket, el tercero es el protocolo (si el argumento
es 0, el sistema selecciona el ms adecuado)
sockf d = socket ( AF_I NET, SOCK_STREAM, 0) ;
i f ( sockf d <0)
er r or ( "Er r or de aper t ur a de socket ") ;
La llamada al socket devuelve un entero, si la llamada falla devuelve -1 y el programa
muestra un mensaje de error y se cierra
La funcin bzer o( ) establece todos los valores en un bfer a cero. Tiene dos
argumentos, el primero es un puntero a la memoria intermedia y el segundo es el
tamao del bfer. Por lo tanto, esta lnea inicializa ser v_addr a ceros.
bzer o( ( char *) &ser v_addr , si zeof ( ser v_addr ) ) ;
Laboratorio de Arquitectura de Redes
- 30 -
El nmero de puerto en el que el servidor escuchar las conexiones se pasa como un
argumento, y esta declaracin utiliza el at oi ( ) para convertir una cadena de dgitos
en un nmero entero.
por t no = at oi ( ar gv[ 1] ) ;
La variable ser v_addr es una estructura de tipo st r uct sockaddr _i n. Esta
estructura tiene cuatro campos, el primer campo es shor t si n_f ami l y que contiene
un cdigo para la familia de direcciones. Siempre se debe establecer en la constante
simblica AF_I NET .
ser v_addr . si n_f ami l y = AF_I NET;
El segundo campo es unsi gned shor t si n_por t , que contiene el nmero de puerto.
ser v_addr . si n_por t = ht ons( por t no) ;
El tercer campo es una estructura del tipo de st r uct i n_addr que contiene slo un
nico campo unsi gned l ong s_addr .
ser v_addr . si n_addr . s_addr = I NADDR_ANY;
Este campo contiene la direccin IP de la mquina. (I NADDR_ANY obtiene esta
direccin.)
La llamada a bi nd( ) enlaza un conector a una direccin, en este caso la direccin de
la mquina actual y el nmero de puerto en el que el servidor se ejecutar. Toma tres
argumentos, el descriptor de fichero socket, la direccin a la que est obligado, y el
tamao de la direccin a la que est enlazado.
El segundo argumento es un puntero a una estructura de tipo sockaddr , pero lo que
ha pasado es una estructura de tipo sockaddr _i n , por lo que se debe convertir al tipo
correcto.
i f ( bi nd ( sockf d, ( st r uct sockaddr *) &ser v_addr , si zeof ( ser v_addr ) ) <0)
er r or ( "Er r or en l a conexi n") ;
La llamada l i st en( ) permite que el proceso quede a la escucha de las conexiones.
El primer argumento es el descriptor de fichero socket, y el segundo es el tamao de la
cola de registro, es decir, el nmero de conexiones que pueden esperar mientras que
el proceso esta operando con una conexin en particular. (5 es el tamao mximo
permitido por la mayora de los sistemas).
l i st en( sockf d, 5) ;
La llamada al sistema accept ( ) hace que el proceso se bloquee hasta que un cliente
se conecta al servidor, el proceso se despierta cuando una conexin de un cliente se
ha establecido con xito.
cl i l en = si zeof ( cl i _addr ) ;
newsockf d = accept ( sockf d, ( st r uct sockaddr *) &cl i _addr , &cl i l en) ;
i f ( newsockf d <0)
er r or ( "Er r or en acept ar ") ;
Devuelve un nuevo descriptor de fichero, y todas las comunicaciones en este sentido
se deben hacer con el nuevo descriptor. El segundo argumento es un puntero de
Laboratorio de Arquitectura de Redes
- 31 -
referencia a la direccin del cliente en el otro extremo de la conexin, y el tercer
argumento es el tamao de esta estructura.
Se debe tener en cuenta que slo se llega a este punto despus de que un cliente se
ha conectado a nuestro servidor. Este cdigo inicializa el buffer mediante la funcin
bzer o( ) , y luego lee desde el socket. La llamada de lectura utiliza el nuevo descriptor
de fichero, el devuelto por accept ( ) , no el descriptor de archivo original devuelto por
socket ( ) .Tambin se bloquear r ead( ) hasta que haya algo para leer, es decir,
despus de que el cliente ha ejecutado un wr i t e( ) .
bzer o ( buf f er , 256) ;
n =r ead( newsockf d, buf f er , 255) ;
i f ( n <0)
er r or ( "Er r or al l eer del socket ") ;
pr i nt f ( "Aqu est el mensaj e: %s ", Buf f er ) ;
Una vez que la conexin ha sido establecida, ambos extremos pueden leer y escribir
en la conexin.
n = wr i t e( newsockf d, "Tengo el mensaj e", 18) ;
i f ( n <0)
er r or ( "Er r or al escr i bi r en el socket ") ;
Todo lo escrito por el cliente ser ledo por el servidor, y todo lo escrito por el servidor
ser ledo por el cliente. Este cdigo simplemente escribe un mensaje corto al cliente.
r et ur n 0;
}
Con esto terminamos el programa principal.
4.3 Descri pcin del programa Cli ente.
Es bastante similar a lo expuesto anteriormente.
En primer lugar colocamos las libreras que contienen declaraciones utilizadas en la
mayora de programas que trabajan con sockets.
#i ncl ude <st di o. h>
#i ncl ude <st dl i b. h>
#i ncl ude <st r i ng. h>
#i ncl ude <uni st d. h>
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
#i ncl ude <net i net / i n. h>
#i ncl ude <net db. h>
Los archivos de cabecera son los mismos que para el servidor con una adicin. El
archivo net db. h define la estructura host ent (***).
La funcin er r or ( ) es idntica a la del servidor, as como las variables sockf d,
por t no, y n
Laboratorio de Arquitectura de Redes
- 32 -
voi d er r or ( char * msg)
{
per r or ( msg) ;
exi t ( 0) ;
}
i nt mai n ( i nt ar gc, char *ar gv[ ] )
{
i nt sockf d, por t no, n;
st r uct sockaddr _i n ser v_addr ;
st r uct host ent *ser ver ;
.La variable ser v_addr contendr la direccin del servidor al que nos queremos
conectar. La variable ser ver es un puntero a una estructura del tipo host ent .
El resto de cdigo es similar a lo expuesto para el servidor.
char buf f er [ 256] ;
i f ( ar gc <3)
{
f pr i nt f ( st der r , "el puer t o host %s est en uso", Ar gv[ 0] ) ;
exi t ( 0) ;
}
por t no = at oi ( ar gv[ 2] ) ;
sockf d = socket ( AF_I NET, SOCK_STREAM, 0) ;
i f ( sockf d <0)
er r or ( "Er r or de aper t ur a de socket ") ;
La variable ar gv[ 1] contiene el nombre de un host a travs de Internet, por ejemplo,
cs. r r r . or g. (Si ejecutamos ambos procesos en una sola mquina, ser el hostname
de la misma)
ser ver = get host byname( ar gv[ 1] ) ;
i f ( ser ver == NULL)
{
f pr i nt f ( st der r , "Er r or , no hay host ") ;
exi t ( 0) ;
}
Si esta estructura es NULL, el sistema no pudo encontrar una mquina con este
nombre.
bzer o( ( char *) &ser v_addr , si zeof ( ser v_addr ) ) ;
ser v_addr . si n_f ami l y = AF_I NET;
bcopy( ( char *) ser ver - >h_addr , ( char *) &ser v_addr . si n_addr . s_addr ,
ser ver - >h_l engt h) ;
ser v_addr . si n_por t = ht ons( por t no) ;
Este cdigo establece los mbitos en los ser v_addr .
La funcin connect es llamada por el cliente para establecer una conexin con el
servidor. Toma tres argumentos, el descriptor de fichero socket, la direccin de la
mquina a la que quiere conectarse (incluyendo el nmero de puerto), y el tamao de
esta direccin.
i f ( connect ( sockf d, ( st r uct sockaddr *) , &ser v_addr , si zeof ( ser v_addr ) )
<0)
er r or ( "Er r or de conexi n") ;
Laboratorio de Arquitectura de Redes
- 33 -
El resto del cdigo pide al usuario que introduzca un mensaje, usa f get s para leer el
mensaje de la entrada estndar, escribe el mensaje en el socket, lee la respuesta y
muestra esta respuesta en la pantalla.
pr i nt f ( "Por f avor , i nt r oduzca el mensaj e: ") ;
bzer o( buf f er , 256) ;
f get s( buf f er , 255, st di n) ;
n = wr i t e( sockf d, buf f er , st r l en( buf f er ) ) ;
i f ( n <0)
er r or ( "Er r or al escr i bi r en socket ") ;
bzer o( buf f er , 256) ;
n = r ead( sockf d, buf f er , 255) ;
i f ( n <0)
er r or ( "Er r or al l eer del socket ") ;
pr i nt f ( "%s ", buf f er ) ;
cl ose( sockf d) ;
r et ur n 0;
}
Todo lo visto anteriormente nos lleva a una nica ejecucin de los servicios del
servidor cuando son requeridos por el cliente. Si deseamos que el servidor siga
proporcionando esos servicios sin tener que ser ejecutado de nuevo, necesitamos que
el proceso sea concurrente, para lo cual debemos realizar una serie de modificaciones
en el cdigo del servidor.
4.4 Descri pcin de Servidor concurrente y secuencial .
El servidor debe funcionar de forma indefinida y debe tener la capacidad de manejar
un nmero de conexiones simultneas, cada una en su propio proceso. Esto se
realiza normalmente por la bifurcacin de un nuevo proceso para manejar cada nueva
conexin.
El siguiente cdigo tiene una funcin ficticia llamada dost uf f ( i nt sockf d) . Esta
funcin se encargar de la conexin despus de que se haya establecido y prestar
los servicios que el cliente solicita.
La declaramos al principio junto a la funcin de error.
voi d dost uf f ( i nt ) ;
Para permitir que el servidor para manejar mltiples conexiones simultneas, hacemos
los siguientes cambios en el cdigo.
1. Poner en accept el siguiente cdigo en un bucle infinito.
2. Despus de establecerse una conexin, se llamar a f or k( ) #### para crear
un nuevo proceso.
3. El proceso hijo se cerrar sockf d ####y se llamara #dost uf f ####,
pasando el descriptor del archivo del nuevo socket como argumento.
Cuando los dos procesos han terminado su transferencia, se indicar en
dost uf f ( ) #### y este terminar.
4. El proceso padre cierra newsockf d ####. Por todo esto es en un bucle
infinito, se vuelve a la instruccin aceptar que esperar a la prxima
conexin.
Laboratorio de Arquitectura de Redes
- 34 -
Este es el cdigo:
whi l e ( 1)
{
newsockf d = accept ( sockf d, ( st r uct sockaddr *) &cl i _addr , &cl i l en) ;
i f ( newsockf d < 0)
er r or ( "ERROR en acept ar ") ;
pi d = f or k( ) ;
i f ( pi d < 0)
er r or ( "ERROR en f or k") ;
i f ( pi d == 0)
{
cl ose( sockf d) ;
dost uf f ( newsockf d) ;
exi t ( 0) ;
}
el se
cl ose( newsockf d) ;
} / * end of whi l e */
Y para la gestin independiente de cada una de las conexiones aadimos la
mencionada funcin dost uf f ( i nt sockf d)
voi d dost uf f ( i nt sock)
{
i nt n;
char buf f er [ 256] ;
bzer o( buf f er , 256) ;
n = r ead( sock, buf f er , 255) ;
i f ( n < 0)
er r or ( "ERROR al l eer del socket ") ;
pr i nt f ( "Aqu est el mensaj e: %s\ n", buf f er ) ;
n = wr i t e( sock, "Tengo el mensaj e", 18) ;
i f ( n < 0)
er r or ( "ERROR al escr i bi r en el socket ") ;
}
(*)
NOMBRE
per r or , er r no - Mensaj es de er r or del si st ema
SI NOPSI S
vac o per r or ( s)
char * s;
# I ncl ude <er r no. h>
i nt sys_ner r ;
char * sys_er r l i st [ ] ;
i nt er r no;
DESCRI PCI N
per r or ( ) pr oduce un mensaj e de er r or br eve en l a nor ma er r or que
descr i be el l t i mo er r or encont r ado dur ant e una l l amada par a un si st ema
o una f unci n de bi bl i ot eca. Si s no es un punt er o NULL y no apunt a a
una cadena, l a cadena apunt a a se i mpr i me, segui da por dos punt os,
segui do de un espaci o, si l owed por el mensaj e y una nueva l nea. Si s
es un punt er o NULL o apunt a a una cadena nul a, sl o se i mpr i me el
mensaj e, segui do de una nueva l nea. Par a ser de mayor ut i l i dad, el
Laboratorio de Arquitectura de Redes
- 35 -
ar gument o cadena debe i ncl ui r el nombr e del pr ogr ama que se i ncur r a el
er r or . El nmer o de er r or se ha t omado del ext er i or var i abl e er r no, que
se est abl ece cuando l os er r or es ocur r i r , per o no bor r a cuando no er r nea
l l amadas. Par a si mpl i f i car el f or mat o de l os mensaj es de l a var i ant e, el
vect or de mensaj e sys_er r l i st cadenas se pr opor ci ona, er r no se puede
ut i l i zar como un ndi ce en est a t abl a par a consegui r l a cadena de
mensaj es si n l a nueva l nea. sys_ner r es el nmer o de mensaj es
si empr e en l a mesa, debe ser r evi sado por que el er r or de nuevo cdi gos
se pueden aadi r al si st ema ant es de que se agr egan a l a mesa.
( **)
st r uct sockaddr _i n
{
shor t si n_f ami l y; / * debe ser AF_I NET * /
u_shor t si n_por t ;
st r uct i n_addr si n_addr ;
si n_zer o char [ 8] ; / * No se ut i l i za, debe ser cer o * /
};
( ***)
st r uct host ent
{
char * h_name; / * nombr e of i ci al del host * /
char ** h_al i ases; / * l i st a de al i as * /
i nt h_addr t ype; / * t i po de di r ecci n de host * /
i nt h_l engt h; / * l ongi t ud de l a di r ecci n * /
char ** h_addr _l i st ; / * l i st a de di r ecci ones de nombr es del ser vi dor * /
# Def i ne h_addr h_addr _l i st [ 0]
/ * Di r ecci n, par a l a compat i bi l i dad haci a at r s * /
};
Def i ne un equi po host en I nt er net . Los mi embr os de est a est r uct ur a son:
h_name Nombr e of i ci al del host .
h_aliases
h_addrtype El t i po de di r ecci n que se devuel ve; act ual ment e, si empr e
AF_I NET.
h_length La l ongi t ud, en byt es, de l a di r ecci n.
h_addr_list Un punt er o a una l i st a de di r ecci ones de r ed par a el host que se
ha l l amado. Di r ecci ones de host se evuel ven en or den de byt es de r ed.
En las pginas siguientes se aaden los listados completos del cliente y los dos
servidores.
Laboratorio de Arquitectura de Redes
- 36 -
4.5 Li stados completos de cdigo.
CLIENTE.C
#i ncl ude <st di o. h>
#i ncl ude <st dl i b. h>
#i ncl ude <uni st d. h>
#i ncl ude <st r i ng. h>
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
#i ncl ude <net i net / i n. h>
#i ncl ude <net db. h>
voi d er r or ( const char *msg)
{
per r or ( msg) ;
exi t ( 0) ;
}
i nt mai n( i nt ar gc, char *ar gv[ ] )
{
i nt sockf d, por t no, n;
st r uct sockaddr _i n ser v_addr ;
st r uct host ent *ser ver ;
char buf f er [ 256] ;
i f ( ar gc < 3)
{
f pr i nt f ( st der r , " El puer t o host %s est en uso\ n" , ar gv[ 0] ) ;
exi t ( 0) ;
}
por t no = at oi ( ar gv[ 2] ) ;
sockf d = socket ( AF_I NET, SOCK_STREAM, 0) ;
i f ( sockf d < 0)
er r or ( " ERROR de aper t ur a de socket " ) ;
ser ver = get host byname( ar gv[ 1] ) ;
i f ( ser ver == NULL)
{
f pr i nt f ( st der r , " ERROR, no hay host \ n" ) ;
exi t ( 0) ;
}
bzer o( ( char *) &ser v_addr , si zeof ( ser v_addr ) ) ;
ser v_addr . si n_f ami l y = AF_I NET;
bcopy( ( char *) ser ver - >h_addr , ( char *) &ser v_addr . si n_addr . s_addr , ser ver - >h_l engt h) ;
ser v_addr . si n_por t = ht ons( por t no) ;
i f ( connect ( sockf d, ( st r uct sockaddr *) &ser v_addr , si zeof ( ser v_addr ) ) < 0)
er r or ( " ERROR de conexi n" ) ;
pr i nt f ( " Por f avor , i nt r oduzca el mensaj e: " ) ;
bzer o( buf f er , 256) ;
f get s( buf f er , 255, st di n) ;
n = wr i t e( sockf d, buf f er , st r l en( buf f er ) ) ;
i f ( n < 0)
er r or ( " ERROR al escr i bi r en socket " ) ;
bzer o( buf f er , 256) ;
n = r ead( sockf d, buf f er , 255) ;
i f ( n < 0)
er r or ( " ERROR al l eer del socket " ) ;
pr i nt f ( " %s\ n" , buf f er ) ;
cl ose( sockf d) ;
r et ur n 0;
}
Laboratorio de Arquitectura de Redes
- 37 -
SERVIDOR.C
#i ncl ude <st di o. h>
#i ncl ude <st dl i b. h>
#i ncl ude <st r i ng. h>
#i ncl ude <uni st d. h>
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
#i ncl ude <net i net / i n. h>
voi d er r or ( const char *msg)
{
per r or ( msg) ;
exi t ( 1) ;
}
i nt mai n( i nt ar gc, char *ar gv[ ] )
{
i nt sockf d, newsockf d, por t no;
sockl en_t cl i l en;
char buf f er [ 256] ;
st r uct sockaddr _i n ser v_addr , cl i _addr ;
i nt n;
i f ( ar gc < 2)
{
f pr i nt f ( st der r , " ERROR, no hay ni ngn puer t o\ n" ) ;
exi t ( 1) ;
}
sockf d = socket ( AF_I NET, SOCK_STREAM, 0) ;
i f ( sockf d < 0)
er r or ( " ERROR de aper t ur a de socket " ) ;
bzer o( ( char *) &ser v_addr , si zeof ( ser v_addr ) ) ;
por t no = at oi ( ar gv[ 1] ) ;
ser v_addr . si n_f ami l y = AF_I NET;
ser v_addr . si n_addr . s_addr = I NADDR_ANY;
ser v_addr . si n_por t = ht ons( por t no) ;
i f ( bi nd( sockf d, ( st r uct sockaddr *) &ser v_addr , si zeof ( ser v_addr ) ) < 0)
er r or ( " ERROR en l a conexi n" ) ;
l i st en( sockf d, 5) ;
cl i l en = si zeof ( cl i _addr ) ;
newsockf d = accept ( sockf d, ( st r uct sockaddr *) &cl i _addr , &cl i l en) ;
i f ( newsockf d < 0)
er r or ( " ERROR en acept ar " ) ;
bzer o( buf f er , 256) ;
n = r ead( newsockf d, buf f er , 255) ;
i f ( n < 0)
er r or ( " ERROR al l eer del socket " ) ;
pr i nt f ( " Aqu est el mensaj e: %s\ n" , buf f er ) ;
n = wr i t e( newsockf d, " Tengo el mensaj e" , 18) ;
i f ( n < 0)
er r or ( " ERROR al escr i bi r en el socket " ) ;
cl ose( newsockf d) ;
cl ose( sockf d) ;
r et ur n 0;
}
Laboratorio de Arquitectura de Redes
- 38 -
SERVIDOR2.C
#i ncl ude <st di o. h>
#i ncl ude <uni st d. h>
#i ncl ude <st dl i b. h>
#i ncl ude <st r i ng. h>
#i ncl ude <sys/ t ypes. h>
#i ncl ude <sys/ socket . h>
#i ncl ude <net i net / i n. h>
voi d dost uf f ( i nt ) ;
voi d er r or ( const char *msg)
{
per r or ( msg) ;
exi t ( 1) ;
}
i nt mai n( i nt ar gc, char *ar gv[ ] )
{
i nt sockf d, newsockf d, por t no, pi d;
sockl en_t cl i l en;
st r uct sockaddr _i n ser v_addr , cl i _addr ;
i f ( ar gc < 2)
{
f pr i nt f ( st der r , " ERROR, no hay ni ngn puer t o\ n" ) ;
exi t ( 1) ;
}
sockf d = socket ( AF_I NET, SOCK_STREAM, 0) ;
i f ( sockf d < 0)
er r or ( " ERROR de aper t ur a de socket " ) ;
bzer o( ( char *) &ser v_addr , si zeof ( ser v_addr ) ) ;
por t no = at oi ( ar gv[ 1] ) ;
ser v_addr . si n_f ami l y = AF_I NET;
ser v_addr . si n_addr . s_addr = I NADDR_ANY;
ser v_addr . si n_por t = ht ons( por t no) ;
i f ( bi nd( sockf d, ( st r uct sockaddr *) &ser v_addr , si zeof ( ser v_addr ) ) < 0)
er r or ( " ERROR en l a conexi n" ) ;
l i st en( sockf d, 5) ;
cl i l en = si zeof ( cl i _addr ) ;
whi l e ( 1)
{
newsockf d = accept ( sockf d, ( st r uct sockaddr *) &cl i _addr , &cl i l en) ;
i f ( newsockf d < 0)
er r or ( " ERROR en acept ar " ) ;
pi d = f or k( ) ;
i f ( pi d < 0)
er r or ( " ERROR en f or k" ) ;
i f ( pi d == 0)
{
cl ose( sockf d) ;
dost uf f ( newsockf d) ;
exi t ( 0) ;
}
el se
cl ose( newsockf d) ;
}
cl ose( sockf d) ;
r et ur n 0;
}
/ *Gest i ona t odas l as comuni caci ones una vez que l a conexi n ha si do est abl eci da*/
voi d dost uf f ( i nt sock)
{
Laboratorio de Arquitectura de Redes
- 39 -
i nt n;
char buf f er [ 256] ;
bzer o( buf f er , 256) ;
n = r ead( sock, buf f er , 255) ;
i f ( n < 0)
er r or ( " ERROR al l eer del socket " ) ;
pr i nt f ( " Aqu est el mensaj e: %s\ n" , buf f er ) ;
n = wr i t e( sock, " Tengo el mensaj e" , 18) ;
i f ( n < 0)
er r or ( " ERROR al escr i bi r en el socket " ) ;
}
4.6 Bibliografa.
UNIX, Programacin avanzada, Ra-ma (2004). Francisco Manuel Mrquez
Garca.
Redes de Computadoras: Un Enfoque Descendente, Pearson Educacin
(2010). J. Kurose & K.W. Ross
Redes de computadoras, Prentice Hall (2003). Andrew S. Tanenbaum
The Linux TCP/IP Stack: Networking for Embedded Systems (2004). Charles
River Media.
Comunicaciones en UNIX, McGraw-Hill, (1992). Rifflet, J. M.
UNIX Network Programming, Prentice Hall (1990). W. R. Stevens.
Internetworking with TCP/IP, Volume I-III, Prentice Hall (1993). D. E. Comer.
David L.Stevens.
Internetworking with TCP/IP. Client-Server programming and applications.
Volume III. Linux-POSIX Socket version, Prentice Hall (2001). D. E. Comer,
David L.Stevens.
TCP/IP Sockets in C: Practical Guide for Programmers, 2 Edition by Michael J.
Donahoo, Kenneth L. Calvert
TCP/IP Protocol Suite, McGraw-Hill (2003). Behrouz A. Forouzan.
http://linux.die.net/man

Anda mungkin juga menyukai