Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 DESARROLLO DE APLICACIONES DISTRIBUIDAS PRÁCTICAS CURSO 2002-2003 SOCKETS en UNIX 1. Los SOCKETS en OSI/ISO - Como ya conocéis, el modelo OSI/ISO estructura los diferentes elementos que conforman una red de comunicación en 7 niveles. Cada capa ofrece sus servicios a los componentes del nivel superior y a su vez usa los servicios de la capa inferior. - Es importante distinguir entre servicios y protocolos: Los servicios de cada capa vienen a ser una interfaz con ésta, mientras que los protocolos definen las forma de las tramas de bits que se intercambian entre capas y el modo en que se efectuará la comunicación. 1.1. Los 7 niveles OSI: NIVEL 1: Capa FÍSICA: Se ocupa de la transmisión de bits a lo largo de un canal de comunicación. NIVEL 2: Capa de ENLACE: Transforma el medio de transmisión (por naturaleza ruidoso) en una línea sin errores. NIVEL 3: Capa de RED: Obtiene paquetes del origen y los encamina por la red hasta su destino. NIVEL 4: Capa de TRANSPORTE: Acepta los datos de la capa de sesión, los divide en unidades más pequeñas y los pasa a la capa de red asegurándose de que llegan a su destino. -1- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 NIVEL 5: Capa de SESIÓN: Permite que los usuarios de distintas máquinas puedan abrir sesiones en máquinas remotas. Por ejemplo, conectarse a un sistema remoto con TELNET o transportar ficheros de una máquina a otra con FTP. NIVEL 6: Capa de PRESENTACIÓN: Se encarga de unificar la sintaxis y la semántica de la información que se transmite. Por ejemplo, resuelve los problemas que puedan surgir de codificaciones de caracteres distintas como ASCII y EBCDIC, o distinta representación de los coma flotante, etc. NIVEL 7: Capa de APLICACIÓN: Ofrece sus servicios al usuario resolviendo los problemas de más alto nivel, como por ejemplo la compatibilidad entre terminales, etc. Un ejemplo es el sistema de ventanas X-WINDOWS. MÁQUINA A APLICACIÓN MÁQUINA B APLICACIÓN PRESENTACIÓN PRESENTACIÓN SESIÓN SESIÓN TRANSPORTE TRANSPORTE RED RED ENLACE ENLACE FÍSICA FÍSICA - Haciendo una similitud con una empresa de transportes, la capa de aplicación sería como el recepcionista que le entrega un formulario al cliente para que éste defina sus necesidades de transporte. La capa de presentación sería por ejemplo el traductor que traduce los datos de un idioma a otro, si por ejemplo se quiere enviar un paquete desde -2- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 Barcelona a Londres. La capa de sesión sería la persona que se encarga de establecer el contacto con las empresas necesarias para que se produzca el envío y recepción en el destino, es decir, establece el sistema: el paquete lo transportará la empresa concertada A hasta el destino donde será distribuido por otra empresa concertada B, etc.... La capa de transporte sería como el embalador del paquete que le pone el sello de origen Barcelona y destino Londres, y que se encargará de recibir la confirmación de que el paquete ha llegado bien. La capa de red, sería el encargado de establecer la ruta por las distintas ciudades. La capa de enlace sería el camionero que se encarga del controlar que el objeto llegue sin errores (accidentes) a su destino. Por último la capa física la formarían el camión y la carretera que son los que permiten físicamente el movimiento del objeto. - Los SOCKETS de UNIX se sitúan en la capa de TRANSPORTE ofreciendo un servicio a la capa superior. El uso de Sockets libera al programador de preocuparse por el canal físico (nivel físico), los errores de la transmisión (nivel enlace), los nodos de la red por donde deben encaminarse las tramas de bits (nivel red), y de la formación de paquetes de información desde el origen al destino (nivel transporte). 2. Familias y tipos de conexión. - Para poder trabajar con sockets hay que conocer algunos aspectos que pertenecen a las capas inferiores. Estos aspectos son la familia o dominio de la conexión y el tipo de conexión. - La familia (o dominio) agrupa los sockets que comparten una serie de características comunes como convenios para formar direcciones de red o para nombrar los objetos de la red. Las familias más comunes en los sistemas UNIX son: a) Familia AF_UNIX: Que usa protocolos internos de Unix. Se suele emplear para comunicar procesos que se ejecutan en una misma máquina ya que no realiza accesos a la red. b) Familia AF_INET: Que usa protocolos de Internet, como el TCP (Transmisión Control Protocol) orientado a conexión o UDP (User Datagram Protocol) no orientado a conexión. Esta familia de sockets es la que usa para comunicar procesos entre máquinas distintas a través de la red. c) Familia AF_CCITT: Que usa la Norma X.25 de CCITT. d) Familia AF_NS: Que usa protocolos NS de XEROX. e) Familia AF_SNA: Protocolos IBM SNA. -3- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 f) Familia AF_DECnet. g) Familia AF_APPLETALK. - El tipo de conexión se refiere al tipo de circuito que se establece entre los dos procesos que se van a comunicar. Hay 2 tipos de circuitos: a) VIRTUAL (orientado a conexión): Mediante la búsqueda de enlaces libres, se establece un circuito virtual entre los dos procesos que se van a comunicar de tal forma que esta conexión ya es permanente hasta el final de la comunicación. Una vez se establece el circuito, los datos se pueden enviar secuencialmente sin preocuparse del circuito por donde pasen (conocido como STREAM o corriente de datos). El tipo de socket que usa el circuito virtual se define como SOCK_STREAM. En la familia AF_INET usan el protocolo TCP. b) DATAGRAMA (no orientado a conexión): Los datagramas no trabajan con circuitos permanentes. La transmisión se realiza a nivel de paquetes de tal forma que cada paquete puede seguir una ruta distinta y por lo tanto no garantiza la recepción secuencial de la información. El uso de datagramas mejora las prestaciones del sistema ya que la red está menos tiempo ocupada aunque obliga al programador a establecer algún mecanismo para garantizar la recepción secuencial de la información. El tipo de socket que usa datagramas se define como SOCK_DGRAM. En la familia AF_UNIX usan el protocolo UDP. Otros tipos de sockets son los SOCK_RAW que usan el protocolo IP de mas bajo nivel. Estos sockets solo están disponibles para el Superusuario. 3. Direcciones de la red. - La dirección de red distingue inequívocamente a cada nodo de la red. - Para hacer referencia a los nodos origen y destino de la conexión, algunas llamadas a los sockets necesitan usar un puntero a una estructura de dirección de socket. Esta estructura está definida en el fichero de cabecera : struct sockaddr { u_short sa_family; char sa_data[14]; }; /* familia de sockets: AF_xxxx */ /* 14 bits con la dirección.*/ /* Su codificación depende de la familia */ -4- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 - Esta estructura general depende de la familia de sockets que se esté usando. Sin embargo, algunas familias han definido su propia estructura para las direcciones de red. Así para la familia AF_INET (con protocolos de Internet) se define en el fichero : struct in_addr{ u_long s_addr; }; struct sockaddr_in { short sin_family; u_short sin_port; in_addr sin_addr; char sin_zero[8]; }; /* 32 bits con la identificación de la red y el host (en binario) */ /*en este caso, AF_INET */ /* 16 bits con el número de puerto */ /* id. red y host */ /* 8 bytes sin usar */ - La estructura equivalente en la familia AF_UNIX emplea direcciones con la forma definida en : struct sockaddr_un{ short sun_family; /* AF_UNIX */ char sun_path[108]; /* Path name */ }; - La dirección de un proceso en la familia UNIX, corresponde en realidad a un nombre de fichero (path) puesto que son procesos que se ejecutan en la misma máquina. - El número de puerto se usa para asociar el socket al proceso que se está ejecutando. Si en una misma máquina hay distintos sockets abiertos cada uno de ellos deberá llevar un número de puerto distinto, puesto que todos llevarán la misma dirección de red. - El número de puerto puede tomar valores entre 1024 y 65535. El sistema proporciona automáticamente números de puerto que estén libres entre 1024 y 5000 mediante ciertas funciones. Del número 1 al 1024 están reservados al sistema y no pueden ser usados por aplicaciones de usuario. - La función int rresvport (int * port) reserva un puerto entre 1024 y 5000. - Si el número de puerto contiene un 0 antes de efectuar la operación BIND, el sistema también le gestionará un número de forma automática. -5- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 3.1. Funciones para la conversión de direcciones. # include # include # include • unsigned long inet_addr (const char * cp) Convierte al formato decimal estándar del usuario apuntado por cp al formato binario definido en la estructura struct in_addr. struct in_addr direccion; ................................. direccion.s_addr = inet_addr(“128.12.10.00”) Las direcciones en internet se dan al usuario en formato decimal formado por números del 0 al 255 separados por puntos, que identifican la red o subred y el número de host. • char * inet_ntoa ( struct in_addr in ) Hace la operación contraria. Devuelve la cadena en decimal dada una estructura in_addr. 3.2. Funciones para la conversión de formatos numéricos. Al comunicar entre dos máquinas distintas, puede ser que cada una de ellas use un formato de almacenamiento numérico distinto: a) big-endian dirección N : byte más significativo dirección N+1 : byte menos significativo : byte menos significativo dirección N+1 : byte más significativo b) little-endian dirección N Por su parte, los protocolos TCP (orientados a conexión) y UDP (no orientados a conexión) usan big-endian. Así se definen las siguientes funciones que realizan las conversiones: # include # include • unsigned long htonl ( unsigned long hostlong ) Convierte un long del formato de la máquina al de la red. • unsigned short htons ( unsigned short hostshort ) -6- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 Convierte un short del formato de la máquina al de la red. • unsigned long ntohl ( unsigned long netlong ) Convierte un long del formato de la red al de la máquina. • unsigned short ntohs ( unsigned short netshort ) Convierte un short del formato de la red al de la máquina. Ejemplo: struct sockaddr_in servidor_addr; ........................................ servidor_addr.sin_port = htons(7000); 4. Llamadas para el manejo de Sockets 4.1. Socket - Apertura de un punto terminal en un canal. #include #include int socket (int af, int type, int protocol); Socket crea un punto terminal para conectarse a un canal bidireccional, devolviendo un descriptor para ese canal. af - Es la familia: AF_UNIX, AF_INET, AF_CCITT, AF_NS, ... type - El tipo de conexión: SOCK_DGRAM (para datagramas) SOCK_STREAM (para virtual), protocol - Es el protocolo particular que se desea usar. Normalmente cada tipo de socket sólo tiene un protocolo, pero si hay más de uno se puede especificar. Si no, se pone un 0. Si todo funciona bien, socket devuelve un descriptor de fichero. En caso contrario devuelve -1, quedando codificado el error en la variable global errno. 4.2. Bind. Nombre de un socket - Bind une un socket a una dirección de red determinada. Su declaración es: #include -7- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 #include /* para la familia AF_UNIX */ #include /* para la familia AF_INET */ int bind(int sfd, const void *addr,int addrlen) - Bind hace que el socket con descriptor sfd se una a la dirección de socket que especifica la estructura apuntada por addr y de longitud addrlen. La estructura a la que apunta addr deberá ser struct sockaddr_un en el caso de la familia AF_UNIX, y será struct sockaddr_in en el caso de la familia AF_INET. - Si la llamada funciona correctamente, bind devuelve 0, en caso contrario -1. 4.3. Listen. Disponibilidad para recibir peticiones de servicio. - En los sockets orientados a conexión, los programas servidores usan listen para indicar que el programa está preparado para recibir peticiones de conexión. #include int listen (int sfd, int backlog) - Listen habilita una cola asociada al socket descrito por sfd para alojar las peticiones de conexión que le realicen otros programas. La longitud de esa cola se especifica en backlog. - Listen sólo tiene sentido en sockets del tipo SOCK_STREAM. - Si listen funciona correctamente devuelve 0, y en caso de error -1. 4.4. Connect. Petición de conexión. - Es la llamada que hace un proceso cliente para empezar a comunicar a través de un socket. #include #include /* para la familia AF_UNIX */ #include /* para la familia AF_INET */ int connect (int sfd,const void *addr,int addrlen) - sfd es el descriptor del socket. -8- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 - addr un puntero a la estructura que contiene la dirección del socket remoto con el que se quiere conectar. Dicha estructura podrá ser struct sockaddr_un o struct sockaddr_in según la familia. - addrlen especifica el tamaño de la estructura. - Si el socket es del tipo SOCK_DGRAM, connect especifica la dirección del socket remoto, pero no se conecta con él. - Si el socket es del tipo SOCK_STREAM, connect intenta una conexión entre el ordenador local y el remoto, quedando la llamada bloqueada hasta que se consigue la conexión o devolviendo un error si no se consigue (cuando está activo el modo de acceso no bloqueante O_NDELAY). - El modo de acceso al socket se puede modificar usando la función fcntl(). fcntl ( sfd, F_SETFL, O_NDELAY ) - La conexión correcta devuelve un 0. Se devuelve -1 en caso de error. 4.5. Accept. Aceptación de conexión. - Los servidores que usan sockets orientados a conexión aceptan las demandas de servicio por medio de la llamada accept. #include int accept(int sfd, void *addr, int *addrlen) - sfd es el descriptor de socket creado por la llamada socket y unido a una dirección con bind. - accept extrae la primera llamada de la cola que ha creado listen sobre el socket, y después crea un nuevo socket con las mismas propiedades que sfd, reservándole un nuevo descriptor de fichero. - Si no hay peticiones para extraer de la cola, accept permanecerá bloqueada a menos que esté activo el control de acceso no bloqueante (O_NDELAY) en cuyo caso devolverá un error. - addr debe apuntar a una estructura local de dirección de socket. La propia llamada accept rellenará esa estructura con la dirección del socket remoto que ha pedido la conexión. -9- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 - addrlen debe ser un puntero para permitir que la llamada sobrescriba sobre él el tamaño real de la dirección leída. - Si no se produce error, accept devolverá el descriptor del nuevo socket creado que corresponderá al socket remoto aceptado. En caso de error devuelve -1. 4.6. Read, readv, recv, recvfrom, recvmsg: Lectura o recepción de mensajes de un socket. a) int read (int sfd, char* buf, unsigned nbyte) - Read lee nbyte bytes del socket sfd y los almacena en el buffer apuntado por buf. Si no hay error, devuelve el número de bytes leídos. b) #include ssize_t readv (int sfd, const struct iovec* iov, size_t iovcnt) - Readv lee los datos del socket sfd y los distribuye entre los distintos buffers especificados por el array iov. El total de elementos de iov viene especificado por iovcnt: iov[0], .., iov[iovcnt-1] - La estructura iovec es la siguiente: struct iovec{ caddr_t iov_base; /* Dirección inicial del buffer */ int iov_len; /* Tamaño en bytes del buffer */ }; - Readv lee hasta encontrar un fin de fichero o completar los buffers, devolviendo el número total de bytes leídos. c) #include int recv (int sfd, void *buf, int len, int flags) int recvfrom (int sfd, void *buf, int len, int flags, void * from, int fromlen) int recvmsg (int sfd, struct msghdr msg[], int flags) - sfd : descriptor del socket del que se lee. - buf : puntero al buffer donde se escriben los datos leídos. - len : número máximo de bytes que cabe en el buffer. - flags: es una combinación de 2 bits: a) MSG_PEEK, que cuando vale 1 el dato leído del socket no se vacía, es decir que se volverá a leer. -10- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 b) MSG_OOB, que cuando vale 1 lee sólo los datos "urgentes" llamados mensajes fuera de banda. Por lo tanto, flags puede valer 0 (00), 1 (01), 2 (10) o 3 (11). Los sockets de la familia AF_UNIX no pueden tener activos ninguno de los dos anteriores. - Las 3 funciones devuelven el total de bytes leídos del socket. - A diferencia de read y readv que pueden leer igual de un descriptor de fichero que de un descriptor de socket, recv, recvfrom y recvmsg sólo pueden leer de un descriptor de socket. - En los sockets SOCK_STREAM, las llamadas sólo pueden usarse después de haber establecido una conexión con CONNECT. En los SOCK_DGRAM no es necesario, si se hace, entonces se recibe siempre del mismo, si no, se recibe de cualquiera. - Recvfrom trabaja igual que recv, pero además puede devolver la dirección del socket desde el que se enviaron los datos. Si from<>NULL, al llamar a la función deberá apuntar a una estructura de dirección de socket, y al volver, la dirección del socket origen se recibirá en la estructura apuntada, y fromlen debe contener el tamaño de la dirección apuntada por from (al llamar a la función, la que tenga from, y al salir la que ha leído realmente) - En los sockets SOCK_STREAM, recvfrom devuelve la misma información que recv ya que al establecer una conexión no devolverá la dirección del socket origen. - En los sockets no orientados a conexión, el mensaje debe leerse en un solo bloque, ya que en otro caso queda truncado. - recvmsg permite que los datos leídos puedan distribuirse entre varios buffers. Así msg es un array de cabeceras de mensaje con la siguiente estructura: struct msghdr { caddr_t msg_name; int msg_namelen; struct iovec* msg_iov; los datos int msg_iovlen; caddr_t msg_accrights; int msg_accrightslen; }; /* dirección de socket (opcional) */ /* tamaño de la dirección de socket */ /* array de buffers sobre los que distribuir leídos */ /* num. de elementos del array msg_iov */ /* derechos de acceso */ /* tamaño de msg_accrights */ -11- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 - msg_name y msg_namelen se usan en los sockets no conectados para conocer la dirección del socket origen o destino. - msg_iov es un array de buffers donde se distribuyen los datos leidos o por enviar. - msg_accrights recoge los derechos de acceso enviados opcionalmente con los mensajes en los sockets de la familia AF_UNIX. 4.7. Write, writev, send, sendto y sendmsg: escritura o envío de mensajes a un socket. - Son las funciones complementarias de read, readv, recv, recvfrom y recvmsg a) int write (int sfd, char* buf, unsigned nbyte) - Write escribe nbyte bytes del buffer apuntado por buf en el socket sfd. Si no hay error, devuelve el número de bytes escritos realmente. b) #include ssize_t writev (int sfd, const struct iovec* iov, size_t iovcnt) - Writev escribe los datos en el socket sfd tomándolos de los distintos buffers especificados por el array iov. El total de elementos de iov viene especificado por iovcnt: - Writev devuelve el número total de bytes escritos. c) #include int send (int sfd, void *buf, int len, int flags) int sendto (int sfd, void *buf, int len, int flags, void * to, int tolen) int sendmsg (int sfd, struct msghdr msg[], int flags) - sfd : descriptor del socket donde se escribe. - buf : puntero al buffer de donde se leen los datos a escribir. - len : número de bytes en el buffer. - flags: puede valer 0 o MSG_OOB. (MSG_PEEK no tiene sentido aquí) - Las 3 funciones devuelven el total de bytes escritos en el socket. - A diferencia de write y writev que pueden escribir igual sobre un descriptor de fichero que sobre un descriptor de socket, send, sendto y sendmsg sólo pueden escribir en un descriptor de socket, tal y como ocurría con recv, recvfrom y recvmsg. -12- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 - En los sockets SOCK_STREAM, las llamadas sólo pueden usarse después de haber establecido una conexión con CONNECT. En los SOCK_DGRAM no es necesario. 4.8. Close. Cierre del canal. int close (int sfd) - La llamada a close cierra el socket en los dos sentidos de recepción y envío. 4.9 Getsockname, getpeername. Obtención de nombres de socket. - Estas llamadas tienen aplicación en los SOCK_STREAM de la familia AF_INET. #Include int getsockname(int sfd, void* addr, int addrlen) int getpeername(int sfd, void* addr, int addrlen) - Getsockname devuelve sobre la estructura apuntada por addr, la dirección del socket de descriptor sfd. - Getpeername devuelve sobre la estructura apuntada por addr, la dirección del socket que se encuentra conectado al socket de descriptor sfd. - addrlen siempre indica el tamaño en bytes de la estructura apuntada por addr. 4.10. Gethostname. Nombre del nodo actual. - Se usa para determinar el nombre oficial que tiene un nodo en la red. #include int gethostname (char* hostname, size_t size) - gethostname devuelve en el array apuntado por hostname el nombre oficial de host del ordenador que hace la llamada. Size contiene la longitud de ese array. -13- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 4.11. Socketpair. Tuberías con sockets. - Crea un par de sockets que permiten la comunicación bidireccional. #include int socketpair(int family, int type, int protocol, int sockvec[2]) - family, type y protocol tiene el mismo significado que en la definición de socket aunque, por ahora, sólo admite la familia AF_UNIX. - sockvec es un vector que contendrá los 2 descriptores de los sockets generados. 4.12. Shutdown. Cierre de socket en un sentido. - Cierra un socket en un único sentido. int shutdown(int sfd, int how) - Si how=0 cierra recepción de datos, 1 cierra envío de datos y 2 cierra ambos. 4.13. Gethostent, gethostbyname, gethostbyaddr, endhostent. Lectura del fichero /etc/hosts. sethostent, - El fichero /etc/hosts contiene la información sobre todas las direcciones internet y los nombres de host de todos los nodos conectados a la red. Si nuestra red tiene un servidor de nombres (DNS), es éste el que resuelve la correspondencia entre direcciones IP y nombres de máquinas. Por ello, en el fichero /etc/hosts local, seguramente sólo veremos las direcciones de la máquina en la que estemos trabajando, y la dirección del servidor DNS. Las siguientes funciones tienen como misión la lectura de dicho fichero si se trabaja sin servidor DNS. En el otro caso, el sistema redireccionará las llamadas al servidor DNS, y éste nos devolverá los datos solicitados. #include #include #include struct hostent* gethostent(); struct hostent* gethostbyname(char* name) -14- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 struct hostent* gethostbyaddr(const char* addr, int len, int type) int sethostent(int stayopen) int endhostname() - La estructura hostent es la siguiente: struct hostent{ char* h_name; char** h_aliases; int h_addrtype; int h_lenght; char** h_addr_list; }; #define h_addr h_addrlist[0] anteriores */ /* Para compatibilizar con versiones - Donde: h_name: nombre oficial del host. h_aliases: array con nombres alternativos del host h_addrtype: Siempre AF_INET. h_lenght: longitud en bytes de la estructura. h_addr_list: array de direcciones de red a las que responde el host. La lista se devuelve en formato de trabajo interno de la máquina (unsigned long), no como cadena de caracteres. - Gethostent: lee la siguiente línea del fichero devolviendo la estructura anterior. Si es la primera, además abre el fichero para lectura. Si es la última, devuelve NULL. - Sethostent abre el fichero para lectura y lo deja preparado para leer en la primera línea. Si además stayopen es distinto de 0, después de cada llamada de gethostent no se cierra el fichero. - Endhostent cierra el fichero. - Gethostbyname lee secuencialmente el fichero hasta encontrar el nombre de host, o su alias, que coincide con name. - Gethostbyaddr hace lo propio con la dirección especificada en la zona de memoria apuntada por addr con longitud len. 4.14. Uname: Información del sistema. -15- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 - Uname es una función no relacionada directamente con los sockets, aunque sí útil para establecer un sistema cliente-servidor. Uname proporciona al cliente información sobre el sistema en el que se está ejecutando el proceso servidor (y viceversa) #include int uname(struct utsname* uname); - Uname devuelve en la estructura apuntada por name la siguiente información: struct utsname{ char sysname[9]; /* nombre del sistema */ char nodename[9]; /* nombre del nodo */ char release[9]; /* edición del sistema operativo */ char version[9]; /* versión del sistema operativo */ char machine[9]; /* tipo de máquina en la que se ejecuta el sistema */ }; -16- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 5. Modelo Cliente-Servidor - Servidor es un proceso que se ejecuta en cualquier nodo de una red y que gestiona el acceso a un determinado recurso. - Cliente es un proceso que se ejecuta en cualquier nodo de la red y que realiza peticiones de servicio al servidor. - Según la forma de atender el servicio, se puede hacer la siguiente clasificación de los servidores: a) Servidores interactivos: - Servidor que además de recoger la petición de servicio se encarga de atenderla él mismo. b) Servidores concurrentes: - Servidor que recoge cada una de las peticiones de los clientes y crea procesos para que se encarguen de atenderlas. Esto es especialmente útil en los servidores que han de atender un gran volumen de peticiones. -17- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 5.1. Esquema general del modelo cliente-servidor. Proceso Servidor Abrir el canal de comunicación Publicar en la red la dirección del canal de comunicación Esperar una petición de servicio fork proceso padre proceso hijo Atender al cliente Fín proceso hijo Esperar respuesta Fín proceso cliente Proceso Cliente Abrir el canal de comunicación Conectar con la dirección del servidor Pedir servicio -18- Sistemas Informáticos Distribuidos. Práctica 1. Los sockets en Unix. SID96PR1.DOC 01/10/2002 19:09 5.2. Esquema Cliente-Servidor con sockets orientados a conexión: Servidor Abre canal socket() bind() listen() accept() Establece conexión Publica dirección Se dispone a recibir peticiones Acepta peticiones Cliente socket() connect() write() read() close() Cierra canal Abre canal Pide conexión read() write() Pide servicio Devuelve respuesta 5.3. Esquema Cliente-Servidor con sockets no orientados a conexión: Servidor Abre canal Cliente socket() bind() Pide servicio socket() bind() revfrom() Devuelve respuesta Publica dirección sendto() revfrom() shutdown() Cierra canal sendto() Bibliografía: • UNIX. Programación Avanzada. F.M.Marquez. ra-ma • Comunicaciones en UNIX. Rifflet. McGraw Hill -19-