Sie sind auf Seite 1von 14

I.E.S. Mar de Cdiz. 2 A.S.I.

2003-2004

Desarrollo de funciones en el sistema informtico

Unidad didctica n 7 DESARROLLO DE APLICACIONES CLIENTE/SERVIDOR MEDIANTE SOCKETS

OBJETIVOS: Conocer las funciones estndar para trabajar con sockets. Disear distintos sistemas de conexin entre aplicaciones. Conocer las diferencias entre un servidor y un cliente. Disear protocolos a nivel de aplicacin. Desarrollar servidores que proporcionen un servicio a un conjunto de clientes.

Ciclo Superior de Administracin de Sistemas Informticos. Asignatura: Profesor: Instituto:


U.D. VII . Sockets

Desarrollo de Funciones en el Sistema Informtico. Fernando Domnguez Cerejido. I.E.S. Mar de Cdiz.
0
Fernando Domnguez

I.E.S. Mar de Cdiz. 2 A.S.I. 2003-2004

Desarrollo de funciones en el sistema informtico

BIBLIOGRAFA
UNIX. Programacin avanzada. (2 Edicin) Fco. Manuel Mrquez. Ed. Ra-ma Programacin en Linux con ejemplos. Kurt Wall. Ed. Prentice - Hall. QUE. Programacin de Socket Linux Sean Walton Ed. Prentice - Hall. Pearson Educacin. www.pearsoneducacion.com DFS. Desarrollo de Funciones en el Sistema Informtico. Juan Carlos Gallego Ramos. Jos Manuel Prez Lobato. Jos Emilio Rico Martnez. Ed. Santillana Profesional. Desarrollo de Funciones en el Sistema Informtico con Linux. Flix Chamorro Atance. Jos Manuel Molina. Araceli Sanchs. Antonio Berlanga. Ed. Mc. Graw-Hill.

U.D. VII . Sockets

Fernando Domnguez

I.E.S. Mar de Cdiz. 2 A.S.I. 2003-2004

Desarrollo de funciones en el sistema informtico

Concepto de socket.
En los aos 80, la agencia ARPA fund un grupo en la Universidad de California en Berkley para implementar el protocolo TCP/IP en el sistema operativo UNIX. Parte del proyecto fue el desarrollo de un interfaz para la comunicacin entre aplicaciones. Los diseadores decidieron utilizar las funciones bsicas de UNIX y aadir alguna ms. El resultado es el interfaz de Sockets para BSD UNIX. Como este sistema de UNIX fue adoptado por muchos vendedores como Sun, DEC, etc., los sockets se han aceptado como un estndar. Cuando los diseadores de Berkley se plantearon el desarrollo de la biblioteca, estudiaron dos opciones distintas: hacer funciones nicamente para el protocolo TCP/IP, o desarrollar funciones que permitieran todo tipo de protocolos y que todos los incluidos en el TCP/IP fueran especificados a travs de una variable. Esta ltima opcin fue la que se eligi y todos los protocolos TCP/IP estn englobados en los sockets de la familia AF_INET (familia de protocolos PF_INET ). En definitiva, el interfaz Socket de Berkley proporciona funciones generales que soportan la comunicacin en redes usando distintos protocolos. Las llamadas a socket hacen referencia a todos los protocolos TCP/IP como si se tratara de un nico protocolo. Adems, cuando el programador realiza las llamadas a las funciones de sockets debe especificar el tipo de servicio requerido (por ejemplo, orientado o no a la conexin) en vez del nombre del protocolo especfico. El interfaz de Berkley crea una nueva abstraccin para la comunicacin en redes, el socket, que no es ms que un nmero entero que hace de ndice en la tabla de descriptores de ficheros del proceso. Cuando un proceso desea realizar una operacin de entrada/salida sobre un fichero, en primer lugar llama a la funcin open() para crear un descriptor de fichero que se usar para acceder a dicho fichero. Cada proceso representa los descriptores de ficheros como un array de punteros; este array es nico para cada proceso. Cuando el proceso abre un fichero se aade un nuevo puntero al array y la funcin open() devuelve el ndice que ocupa dentro del array. Puesto que los descriptores de fichero y los descriptores de sockets se almacenan en la misma tabla, no puede haber dos iguales. As pues, para poder utilizar un socket es necesario obtener un descriptor, es decir, un elemento en la tabla de descriptores de ficheros, en el cual se guarda un puntero a una estructura de datos que determina los parmetros del socket .

Estructuras de datos necesarias.


En principio, un socket no tiene predefinido el uso al que se le destina, por ejemplo, no aparecen ni la direccin local IP, ni el puerto local, ni la direccin remota, ni el puerto remoto, etc. Esto es as, porque la abstraccin socket debe ser vlida para cualquier familia de protocolos, por lo que la especificacin de los extremos de la comunicacin debe quedar abierta segn la familia. La interfaz de sockets define una familia de direcciones para cada uno de los tipos posibles de direccionamiento, por lo que en realidad el programador, al especificar la familia que va a usar, est indicando el tipo de direcciones que usar. Es decir, en general, la forma de definir un socket es especificar la familia de direcciones y, segn esto, especificar el extremo de la comunicacin. P.e., en el caso del protocolo TCP/IP, esa familia de direcciones se representa por la constante AF_INET y un extremo se define a travs de su direccin IP y su puerto. Por tanto, la estructura ms general -denominada sockaddr- slo requiere una familia de direcciones y una direccin.
#include <sys/socket.h> struct sockaddr { u_short sa_family; //familia de direcciones char sa_data[14]; //direccin concreta };

U.D. VII . Sockets

Fernando Domnguez

I.E.S. Mar de Cdiz. 2 A.S.I. 2003-2004

Desarrollo de funciones en el sistema informtico

El valor de sa_family (sa= stored address) es tpicamente uno de los valores siguientes:
Familia de direcciones Familia de protocolos Descripcin

AF_UNIX AF_INET AF_AX25 AF_IPX AF_APPLETALK

PF_UNIX PF_INET PF_AX25 PF_IPX PF_APPLETALK

Sockets de entorno UNIX TCP/IP Protocolo AX.25 para radioaficionados Protocolo Novell IPX Protocolo Apple Talk DDS

En realidad, la definicin de la estructura anterior tan general no es vlida para cualquier familia; por ejemplo, la familia AF_UNIX , que define los pipes, puede utilizar una direccin mediante un path cuya longitud en caracteres exceda los 14 que estn definidos en la estructura sockaddr. Cada familia tiene su propia estructura para definir los extremos de un enlace. En el caso de las aplicaciones que usan TCP/IP, el extremo se define mediante una estructura compuesta de 2 bytes para la familia, 2 bytes para el nmero de puerto, 4 bytes para la direccin IP y 8 bytes que estn sin usar. Su definicin, incluida en <netinet/in.h>, es la siguiente:
struct sockaddr_in { u_short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; struct in_addr { u_long s_addr; };

//tipo de direccin 2 bytes //nmero de puerto 2 bytes //direccin IP 4 bytes

Esquema genrico de un servidor y un cliente.


La forma genrica que van a tener los diagramas de flujo de control, tanto de los procesos servidores como de los clientes, se puede ver a continuacin: Las acciones que debe llevar a cabo el programa servidor son las siguientes: Abrir el canal de comunicaciones e informar a la red tanto de la direccin a la que responder como de su disposicin para aceptar peticiones de servicio. Esperar a que un cliente le pida servicio en la direccin que l tiene declarada. Cuando recibe una peticin de servicio, Si es un servidor interactivo, acceder al cliente. Los servidores interactivos se suelen implementar cuando la respuesta que necesita el cliente es sencilla e implica poco tiempo de proceso. Si el servidor es concurrente, crear un proceso mediante fork() , para que le d servicio al cliente. El programa cliente, por su parte, llevar a cabo las siguientes acciones: Abrir el canal de comunicaciones y conectarse a la direccin de red atendida por el servidor. Naturalmente, esta direccin debe ser conocida por el cliente y responder al esquema de generacin de direcciones de la familia de conectores que se est empleando. Enviar al servidor un mensaje de peticin de servicio y esperar hasta recibir la respuesta. Cerrar el canal de comunicaciones y terminar la ejecucin.

U.D. VII . Sockets

Fernando Domnguez

I.E.S. Mar de Cdiz. 2 A.S.I. 2003-2004

Desarrollo de funciones en el sistema informtico

Uso de las funciones en programas.


#include <sys/types.h> #include <sys/socket.h> //no es necesaria en listen()

int socket (int familia, int tipo, int protocolo); int bind (int sfd, struct sockaddr *dir_local, socklen_t longitud_dir); int listen (int sfd, int longitud_cola); int connect (int sfd, const struct sockaddr *direccion, socklen_t longitud_dir); int accept (int sfd, struct sockaddr *dir, socklen_t *longitud_dir);

El proceso cliente comienza por crear un socket llamando a la funcin socket() . Posteriormente, lo conecta a un servidor mediante la funcin connect(). A travs esa conexin puede escribir y leer de forma ininterrumpida hasta que se ha obtenido toda la informacin deseada o hasta que el servidor enva un cdigo de terminacin de conexin. Cuando el cliente desea desconectarse del servidor, cierra el socket con una llamada a close(). En el caso del servidor, en primer lugar se crea el socket y despus se liga a una direccin local (direccin IP y puerto local) mediante la funcin bind(). A travs de esa direccin, y mediante una llamada a la funcin listen() -define el socket como pasivo-, se escuchan las posibles peticiones de conexin. Cuando se recibe una peticin de conexin, el servidor habitualmente- la acepta mediante la funcin accept(). A travs de la conexin que se ha establecido, el servidor puede escribir y recibir datos del proceso cliente. Es evidente que ambos procesos deben estar de acuerdo en escribir y leer, alternativamente, de manera que la informacin que se comunican sea un dilogo entre aplicaciones, y no traten de enviar o recibir las dos al mismo tiempo. Este proceso de entendimiento es labor del programador: la definicin de cmo se entienden las dos aplicaciones es lo que se denomina protocolo de aplicacin. Una vez que se decide terminar la conexin, el servidor cierra el socket mediante una llamada a close().
U.D. VII . Sockets

Fernando Domnguez

I.E.S. Mar de Cdiz. 2 A.S.I. 2003-2004

Desarrollo de funciones en el sistema informtico

Funciones para el manejo de direcciones.


Para almacenar las direcciones de red TCP/IP se utiliza la estructura antes vista sockaddr_in , donde los campos sin_port y sin_addr deben estar expresados en el orden de bytes de la red. Vemoslo detalladamente:
struct sockaddr_in { u_short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; }; struct in_addr { u_long s_addr; };
// tipo de direccin // nmero de puerto // direccin IP

El protocolo TCP/IP es de tipo big-endian, es decir, almacena el bit ms significativo de los nmeros multibyte en la direccin de memoria ms baja. Sin embargo, los procesadores Intel x86 y sus compatibles, son de tipo little-endian, lo que quiere decir que en los nmeros multibyte se almacena en la direccin de memoria ms baja el byte menos significativo. Para hacer las conversiones oportunas existen las siguientes funciones:
#include <netinet/in.h> unsigned unsigned unsigned unsigned long int htonl (unsigned long int hostlong); short int htons (unsigned short int hostshort); long int ntohl (unsigned long int netlong); short int ntohs (unsigned short int netshort);

htonl convierte un long desde el orden de bytes del sistema al orden de bytes de la red. htons convierte un short desde el orden de bytes del sistema al orden de bytes de la red. ntohl convierte un long desde el orden de bytes de la red al orden de bytes del sistema. ntohs convierte un short desde el orden de bytes de la red al orden de bytes del sistema.
EJEMPLO:

...... #define PUERTO_SERVIDOR_TCP 7000 int main(void) { struct sockaddr_in servidor_addr; ...... servidor_addr.sin_port = htons (PUERTO_SERVIDOR_TCP); ......

Por otro lado, sin_addr es una estructura binaria, de modo que ...
#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int inet_aton (const char *cad_dir, struct in_addr *ip_dir); char *inet_ntoa (struct in_addr direccion);

para convertir una direccin en forma decimal con puntos al formato binario se debe utilizar la funcin inet_aton() recprocamente, para pasar del formato binario a la notacin estndar decimal con puntos se debe emplear la funcin inet_ntoa()
U.D. VII . Sockets

Fernando Domnguez

I.E.S. Mar de Cdiz. 2 A.S.I. 2003-2004

Desarrollo de funciones en el sistema informtico

EJEMPLO:

...... #define DIRECCION_SERVIDOR_TCP 192.168.1.1" .... int main(void) { struct sockaddr_in servidor_addr; ...... inet_aton ( DIRECCION_SERVIDOR_TCP, &servidor_addr.sin_addr); ......

Funciones que obtienen informacin de la mquina.


gethostname()
#include <unistd.h> int gethostname(char *nombre, size_t longitud_nombre);

Devuelve el nombre principal de la mquina local mediante una cadena de caracteres. nombre es un puntero a una cadena de caracteres que contendr el nombre de la mquina local. longitud_nombre es la longitud del array anterior, al menos de 65. Devuelve 0 si el funcionamiento fue correcto, y -1 en caso de error, conteniendo la variable global errno el valor apropiado.

gethostbyname()
#include <netdb.h> struct hostent *gethostbyname(const char *nombre);

Permite obtener informacin de una mquina si se indica el nombre de la misma. La estructura hostent se define de la siguiente manera:
struct hostent { char *h_name; char **h_aliases; int h_addrtype; int h_length; char **h_addr_list; };

//nombre oficial del host //lista de alias alternativos //tipo de direccin: AF_INET //longitud de la direccin //lista de direcc. para host

U.D. VII . Sockets

Fernando Domnguez

I.E.S. Mar de Cdiz. 2 A.S.I. 2003-2004

Desarrollo de funciones en el sistema informtico

Funciones para el manejo de socket.


socket()
Se usa para abrir un canal bidireccional de comunicaciones: crea un punto terminal para conectarse a un canal y devuelve un descriptor.
#include <sys/types.h> #include <sys/socket.h> int socket (int familia, int tipo, int protocolo);

familia

es la familia de direcciones que se va a usar. La constante PF_INET (o tambin, AF_INET) es la que se usa para emplear los protocolos de Internet, tales como TCP, o bien, UDP. La constante AF_UNIX se especifica para los protocolos internos UNIX, es decir, cuando se va a emplear una familia de direcciones para comunicar procesos que se ejecutan en una misma mquina, y que por tanto no requiere que est presente un hardware especial de red. es el tipo de servicio, y puede tomar dos valores: SOCK_STREAM para TCP (protocolo orientado a conexin). Acepta secuencia de caracteres (streams) orientadas a conexin, secuenciadas, con control de errores y full duplex. SOCK_DGRAM para UDP (datagrama o protocolo no orientado a conexin). Acepta mensajes sin conexin, sin orden secuencial, sin control de errores y orientados a paquetes de datos de tamao fijo. es el nmero de protocolo que se va a emplear; si vale 0 hace que se tome el valor por defecto para una determinada familia.

tipo

protocolo

Si la funcin se ejecuta correctamente devuelve un entero positivo que corresponde al valor de descriptor; en caso contrario, si ocurre algn error, devuelve -1 y en la variable errno se almacena el cdigo que especifica la causa del error:
EPROTONOSUPPORT EINVAL EMFILE ENFILE EACCESS ENOBUFS Servicio requerido o protocolo especificado no son vlidos. Familia o protocolo desconocidos. La tabla de descriptores de ficheros del proceso est llena. La tabla de ficheros del sistema est llena. Carece del permiso necesario para la creacin del socket. El sistema no tiene espacio de buffer disponible.

bind()
Se utiliza para unir un conector (sfd) con una direccin de red determinada (dir_local) . Suele ser usada en servidores que desean definir un determinado puerto para permanecer a la escucha de posibles intentos de conexin de clientes.
#include <sys/types.h> #include <sys/socket.h> int bind (int sfd, struct sockaddr *dir_local, socklen_t longitud_dir);

U.D. VII . Sockets

Fernando Domnguez

I.E.S. Mar de Cdiz. 2 A.S.I. 2003-2004

Desarrollo de funciones en el sistema informtico

sfd dir_local

es el descriptor del socket que fue creado por una llamada a socket(). es la direccin de la mquina local. Su formato depende de la familia del conector: para la familia AF_INET se usa la estructura sockaddr_in . El campo sin_port de sta puede contener el nmero de un puerto o el valor 0, en cuyo caso el sistema le asigna el nmero de un puerto libre. es la longitud del segundo argumento. Se puede calcular con el operador sizeof.

longitud_dir

Si la funcin se ejecuta correctamente devuelve un 0; en caso contrario, si ocurre algn error, devuelve -1 y en la variable errno se almacena el cdigo que especifica la causa del error:
EBADF ENOTSOCK EADDRNOTAVAIL EADDRINUSE EFAULT EINVAL EACCES El primer argumento no es un descriptor vlido. El primer argumento no especifica un descriptor de socket. La direccin especificada no est disponible (p.e., si la direccin IP especificada no coincide con la direccin de la mquina local) . La direccin especificada est ocupada (p.e., otro proceso ha podido conectarse a este puerto). El puntero que representa la direccin local es invlido. El socket ya est ligado a otra direccin. El proceso no tiene permisos para acceder a ese puerto.

listen()
Mediante esta llamada, cuando se abre un conector orientado a conexin, el programa servidor indica que est disponible para recibir peticiones de conexin. As pues, esta funcin permite a los servidores caracterizar al socket como pasivo y preparado para aceptar informacin externa; adems, habilita una cola encargada de alojar peticiones de conexin procedentes de los procesos clientes. Mediante su segundo argumento se especifica el nmero de conexiones que como mximo van a ser colocadas en la cola de peticiones de conexin, mientras el servidor atiende a otros clientes.
#include <sys/socket.h> int listen (int sfd, int longitud_cola);

sfd

es el descriptor del socket que fue creado por una llamada a socket().

longitud_cola es el tamao de conexiones para la cola de peticiones (habitualmente es 5). Si la funcin se ejecuta correctamente devuelve un 0; en caso contrario, si ocurre algn error, devuelve -1 y en la variable errno se almacena el cdigo que especifica la causa del error:
EBADF ENOTSOCK EOPNOTSUPP El primer argumento no es un descriptor vlido. El primer argumento no especifica un descriptor de socket. El tipo de socket no soporta la funcin listen().

connect()
La usa el proceso cliente para iniciar una conexin con un servidor a travs de un conector.
#include <sys/types.h> #include <sys/socket.h> int connect (int sfd, const struct sockaddr *direccion, socklen_t longitud_dir);
U.D. VII . Sockets

Fernando Domnguez

I.E.S. Mar de Cdiz. 2 A.S.I. 2003-2004

Desarrollo de funciones en el sistema informtico

sfd direccion longitud_dir

es el descriptor de un socket, creado por una llamada a socket(). es la direccin de la mquina remota es la longitud del segundo argumento.

Si la funcin se ejecuta correctamente devuelve un 0, en caso contrario, si ocurre algn error, devuelve -1 y en la variable errno se almacena el cdigo que especifica la causa del error:
EBADF ENOTSOCK EAFNOSUPPORT EADDRNOTAVAIL EISCONN ETIMEDOUT ECONNREFUSED ENETUNREACH EADDRINUSE EINPROGRESS EALREADY El primer argumento no es un descriptor vlido. El primer argumento no especifica un descriptor de socket. La familia de direcciones especificada en el punto remoto no puede ser utilizada en este tipo de socket. La direccin especificada no est disponible. El socket ya est conectado. El tiempo para intentar la conexin ha excedido del timeout prefijado (slo para TCP). Conexin rechazada por la mquina remota (slo para TCP). No es posible encontrar la red (slo para TCP). La direccin especificada est ocupada. El socket no est bloqueado y una posible conexin podra bloquearlo (slo para TCP). El socket no est bloqueado y una posible llamada esperara a que se completara una conexin previa (slo para TCP).

Si el conector es del tipo SOCK_DGRAM, esta funcin especifica la direccin del conector remoto al que se le van a enviar los mensajes, pero no se conecta con l. La llamada devuelve el control inmediatamente. Adems, a travs del conector slo se podrn recibir mensajes procedentes de la direccin especificada. Si el conector es del tipo SOCK_STREAM, esta funcin intenta contactar con el ordenador remoto con objeto de realizar una conexin entre el conector remoto y el conector local especificado en sfd. La llamada normalmente permanece bloqueada hasta que la conexin se completa. Por el contrario, si la conexin no se puede realizar de forma inmediata, pero el conector tiene activo el modo de acceso O_NDELAY -activado a travs de una llamada a fcntl()-, la llamada a connect() devuelve el control inmediatamente indicando que se ha producido un error de conexin.

accept()
Se usa con conectores orientados a conexin (socket de tipo stream). Sirve para que los procesos servidores lean peticiones de servicio. Mediante ella se borra (se extrae) una peticin de conexin de la cola (o se espera a que se produzca una peticin de conexin), se crea un nuevo socket para la peticin (con las mismas propiedades que sfd), y se devuelve el descriptor del nuevo socket. El conector original (sfd) permanece abierto, a la escucha; no se ve afectado por esta llamada y puede aceptar nuevas conexiones; sin embargo, el conector recin creado (nsfd) no puede usarse para aceptar ms conexiones.
#include <sys/types.h> #include <sys/socket.h> int accept (int sfd, struct sockaddr *dir, socklent_t *longitud_dir);
U.D. VII . Sockets

Fernando Domnguez

I.E.S. Mar de Cdiz. 2 A.S.I. 2003-2004

Desarrollo de funciones en el sistema informtico

sfd dir longitud_dir

es el descriptor del socket que fue creado por una llamada a socket(). es una estructura que la llamada a accept() rellena con la direccin de la entidad con la que se conecta. es, inicialmente, la longitud del segundo argumento, y posteriormente, el nmero de bytes almacenados en el segundo argumento, o sea, el tamao real de la direccin leda de la cola de conexiones.

Si la funcin se ejecuta correctamente devuelve un valor entero positivo que define un descriptor; en caso contrario, si ocurre algn error, devuelve -1 y en la variable errno se almacena el cdigo que especifica la causa del error :
EBADF ENOTSOCK EFAULT EWOULDBLOCK EOPNOTSUPP El primer argumento no es un descriptor vlido. El primer argumento no especifica un descriptor de socket. El puntero que representa la direccin remota es invlido. El socket se ha definido como E/S no bloqueada y no se esperan conexiones a aceptar. El tipo de socket no es SOCK_STREAM

Si no hay peticiones de conexin pendientes, y el conector no tiene activo el modo de acceso no bloqueante (O_NDELAY), esta funcin permanece bloqueada hasta que se reciba una nueva peticin de conexin. Si el modo no bloqueante est activo, esta funcin devolver el control inmediatamente e indicar que se ha producido un error.

write()
Sirve para transmitir datos entre mquinas distintas.
int write (int socket, char *buffer, int longitud_buf);

socket buffer longitud_buf

es el descriptor de un socket, creado por una llamada a socket(). es la direccin de un espacio reservado que contiene datos. es la longitud del segundo argumento.

Si la funcin se ejecuta correctamente devuelve un entero positivo que representa el nmero de bytes transmitidos; en caso contrario, si ocurre algn error, devuelve -1 y en la variable errno se almacena el cdigo que especifica la causa del error :
EBADF EPIPE EFBIF EFAULT EINVAL EIO EWOULDBLOCK El primer argumento no es un descriptor vlido. Intento de escritura en un socket desconectado. La cantidad de datos excede de la capacidad del sistema. La direccin del puntero buffer es incorrecta. El valor del socket es invlido. Error de entrada/salida. El socket no puede aceptar todos los datos, si no, se bloquea, pero se ha definido una entrada/salida no bloqueada.

U.D. VII . Sockets

10

Fernando Domnguez

I.E.S. Mar de Cdiz. 2 A.S.I. 2003-2004

Desarrollo de funciones en el sistema informtico

read()
Sirve para que se reciban datos de mquinas remotas.
int read (int socket, char *buffer, int longitud_buf);

socket buffer longitud_buf

es el descriptor de un socket, creado por una llamada a socket(). es la direccin de un espacio reservado que contiene datos. es la longitud del segundo argumento.

Si la funcin se ejecuta correctamente devuelve un entero positivo que representa el nmero de bytes recibidos; en caso contrario, si ocurre algn error, devuelve -1 y en la variable errno se almacena el cdigo que especifica la causa del error :
EBADF EFAULT EINTR EIO EWOULDBLOCK El primer argumento no es un descriptor vlido. La direccin del puntero buffer es incorrecta. Una seal ha interrumpido la lectura. Error de entrada/salida. Se ha especificado una E/S no bloqueada pero el socket no contiene datos.

close()
Es responsable de terminar la comunicacin y de eliminar el socket; los datos que se encuentran esperando en el socket sern desechados. Todas las aplicaciones que usan sockets deben llamar a esta funcin cuando se termina de trabajar con l. En principio, UNIX tiene un mecanismo de control que permite a varios procesos acceder al mismo socket; el sistema lleva la cuenta del nmero de procesos y lo va decrementando a medida que se llama a la funcin close(), al llegar a 0 el socket se elimina.
int close (int socket);

socket

es el descriptor del socket que se desea cerrar y que fue creado por una llamada a socket().

Si la funcin se ejecuta correctamente devuelve un 0; en caso contrario, si ocurre algn error, devuelve -1 y en la variable errno se almacena el cdigo que especifica la causa del error; puede tomar uno de los siguientes valores:
EBADF El primer argumento no es un descriptor vlido.

U.D. VII . Sockets

11

Fernando Domnguez

I.E.S. Mar de Cdiz. 2 A.S.I. 2003-2004

Desarrollo de funciones en el sistema informtico

Ejemplos Los programas ejemplo que se comentan a continuacin se encuentran en su correspondiente carpeta nominadas de la forma ?_ejemplo- y se han compilado conjuntamente con el fuente comun_socket.c (que incluye a comun_socket.h) puesto que usan las funciones incluidas en dicho fuente. 1_ejemplo: El programa servidor acepta la primera peticin de conexin de un programa cliente, y mediante la funcin transfiere_datos() lee lo que el cliente enva a travs del socket y lo muestra en pantalla. Por su parte, el programa cliente se ejecuta dando la direccin IP del servidor como 1 argumento en lnea de rdenes, y usando la funcin antes mencionada, lee datos del teclado y lo enva a travs del socket al programa servidor. 2_ejemplo: El programa servidor acepta la primera peticin de conexin de un programa cliente, y mediante la funcin lee_escribe_serv() intercambia datos con el cliente; es decir, lo que enva el cliente a travs del socket lo muestra en pantalla, y a continuacin, lee del teclado y lo enva al cliente a travs del socket. Y as sucesivamente. Por su parte, el programa cliente se ejecuta dando la direccin IP del servidor como 1 argumento en lnea de rdenes, y usando la funcin lee_escribe_cliente(), lee datos del teclado y lo enva a travs del socket al programa servidor, y luego queda a la espera de recibir datos del servidor a travs del socket para mostrarlos en pantalla. Y as sucesivamente. 3_ejemplo: Igual que el ejemplo 2 con la nica diferencia de que el servidor acepta un nmero indeterminado de peticiones de conexin de los clientes, creando un hijo por cada una de ellas, cada uno de los cuales intercambiar datos con el correspondiente cliente. 4_ejemplo: Programa que da informacin de la mquina sobre la que se ejecuta: nombre del host, alias, direcciones almacenadas, etc.. La funcin informacin_maquina() incluida en el fuente comun_socket.c realiza un trabajo similar aunque usando una sintaxis diferente. 5_ejemplo: Similar al ejemplo 2, pero utiliza sockets de la familia UNIX, es decir, el programa servidor y el cliente intercambiarn informacin en la misma mquina creando un archivo socket- a travs del cual se comunicarn. 6_ejemplo: El programa servidor acepta mltiples peticiones de conexin de programas clientes que enviarn ficheros. Por cada cliente que pide conexin se crea un hijo para atenderla. Cada hijo lee en primer lugar un mensaje cabecera donde el cliente indica su PID, el nombre del fichero que enviar y el tamao de ste; luego, el hijo va leyendo los bloques de informacin que le manda el cliente a travs del socket y va grabando el fichero en su directorio actual. El fichero queda con el mismo nombre, con los mismos permisos y con la misma fecha-hora que el original. Por su parte, el programa cliente se ejecuta dando la direccin IP del servidor como 1 argumento en lnea de rdenes, y el nombre del path del fichero que le enviar como 2 argumento.

U.D. VII . Sockets

12

Fernando Domnguez

I.E.S. Mar de Cdiz. 2 A.S.I. 2003-2004

Desarrollo de funciones en el sistema informtico

Proyecto de programacin Modificar y ampliar el ejemplo 6 de forma que: El cliente se autentificar ante el servidor, el cual usar un fichero de registros con los nombres de los usuarios autorizados, sus contraseas, capacidad lmite asignada a su directorio, fechahora de la ltima conexin, etc.. Para ello dar en lnea de rdenes el indicador /usu:nombre_usuario. En el directorio en que se ejecute el programa servidor existir una carpeta por cada usuario de modo que cada uno grabar/leer los archivos en/de su carpeta. Adems existir (por defecto) un usuario Annimo que no necesitar contrasea y su carpeta se llamar comun. El servidor grabar un fichero de texto llamado <operaciones> en el que aadir una lnea por cada peticin de los programas cliente describiendo la operacin solicitada y el resultado de la misma (si fue terminada con xito, si fall, si fue abortada, etc.). Ser necesario establecer un lmite de ocupacin en los directorios de forma que antes de grabar se compruebe si se sobrepasa el lmite, y en su caso, abortar la operacin, mandando un mensaje al cliente con tal indicacin. El directorio <comun> podr tener un lmite superior al resto. El servidor no grabar el fichero si existe uno con el mismo nombre en el directorio de destino. Deber enviar un mensaje de aviso al cliente indicndole tal incidencia. El cliente podr realizar diversas operaciones en funcin del indicador que escriba en lnea de rdenes como 3 parmetro: Enviar un fichero a su directorio (o al directorio <comun>) si especifica el indicador /envio:fichero Podr solicitar recibir un fichero del servidor especificando /recibo:fichero Podr borrar un fichero indicando /borro:fichero. De la carpeta <comun> no se podrn borrar ficheros. Si indica /lista o no indica nada recibir una lista de los ficheros existentes. De esta forma, la sintaxis para ejecutar el cliente queda de la forma: # cli_tcp X.X.X.X /usu:nombre {[/envio:fichero]|[/recibo:fichero]|[/borro:fichero]|[/lista] }

U.D. VII . Sockets

13

Fernando Domnguez

Das könnte Ihnen auch gefallen