Sie sind auf Seite 1von 20

Prctica3: Programacin POSIX

Programacin y Administracin de Sistemas


2011-2012
Javier Snchez Monedero
jsanchezm@uco.es

2o curso de Grado en Ingeniera Informtica


Departamento de Informtica y Anlisis Numrico
Escuela Politcnica Superior
Universidad de Crdoba
26 de octubre de 2012
Resumen
Entre otras cosas, el estndar POSIX define una serie de funciones (comportamiento,
parmetros y valores devueltos) que deben proporcionar todos los sistemas operativos
que quieran satisfacer el estndar. De esta forma, si una aplicacin hace un buen uso de
estas funciones deber compilar y ejecutarse sin problemas en cualquier sistema operativo
POSIX. En esta prctica vamos a conocer qu es el estndar POSIX, y una implementacin de la biblioteca C de POSIX, la biblioteca libre GNU C Library o glibc. En Moodle se
adjunta el fichero pas-practica3.tgz que contiene cdigo de ejemplo de las funciones que iremos viendo en clase.

ndice
1. Introduccin a POSIX

2. Objetivos

3. Entrega de prcticas

4. Documentacin de POSIX y las bibliotecas

5. Procesado de lnea de comandos tipo POSIX


5.1. Introduccin y documentacin . . . . . . . . . . . . . . . . . . . . . . . . . . .
5.2. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

4
4
5

6. Variables de entorno
6.1. Introduccin y documentacin . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.2. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

5
5
6

Programacin y Administracin de Sistemas 2011-2012

7. Obtencin de informacin de un usuario/a


7.1. Introduccin y documentacin . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

6
6
6

8. Ejercicio resumen 1 (0.5 punto)

9. Creacin de procesos Fork y Exec


9.1. Introduccin y documentacin . . . . . . . . . . . . . . . . . . . . . . . . . . .
9.2. Ejercicios y ejemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7
7
8

10. Seales entre procesos


10.1. Introduccin y documentacin . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.2. Ejercicios y ejemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11
11
11

11. sockets POSIX


11.1. Introduccin y conceptos bsicos . . . . . . .
11.2. Algoritmo bsico Cliente-Servidor . . . . . .
11.3. Pasos de programacin C en el lado Servidor
11.4. Pasos de programacin C en el lado Cliente .

.
.
.
.

12
12
13
14
14

12. Todo junto: un servidor web bsico en C


12.1. Introduccin y cdigo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12.2. Ejercicios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15
15
16

13. Ejercicio resumen 2 (1 punto)

17

14. Trabajo futuro

18

Referencias

18

1.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

.
.
.
.

Introduccin a POSIX

POSIX es el acrnimo de Portable Operating System Interface; la X


viene de UNIX como sea de identidad de la API (Application Programming Interface, interfaz de programacin de aplicaciones). Son una
familia de estndares de llamadas al sistema operativo definidos
por el IEEE (Institute of Electrical and Electronics Engineers, Instituto
de Ingenieros Elctricos y Electrnicos) y especificados formalmente
en el IEEE 1003. Persiguen generalizar las interfaces de los sistemas
operativos para que una misma aplicacin pueda ejecutarse en distintas plataformas. Estos estndares surgieron de un proyecto de
normalizacin de las API y describen un conjunto de interfaces de Figura 1: Mascota del
aplicacin adaptables a una gran variedad de implementaciones de proyecto GNU (http:
sistemas operativos [1]. La ltima versin de la especificacin POSIX es
del ao 2008, se cono//www.gnu.org/)
ce por POSIX.1-2008, IEEE Std 1003.1-2008 y por The Open Group Technical Standard
Base Specifications, Issue 7[2].

1. Introduccin a POSIX

Figura 2: Dennis MacAlistair Ritchie. Colabor en el diseo y desarrollo de los sistemas


operativos Multics y Unix, as como el desarrollo de varios lenguajes de programacin como
el C, tema sobre el cual escribi un clebre clsico de las ciencias de la computacin junto a
Brian Wilson Kernighan: El lenguaje de programacin C [4].
GNU C Library, comnmente conocida como glibc es la biblioteca estndar de lenguaje
C de GNU. Se distribuye bajo los trminos de la licencia GNU LGPL. Esta biblioteca sigue
todos los estndares ms relevantes como ISO C99 y POSIX.1-2008 [3]. gnulib, tambin
conocida como Biblioteca de portabilidad de GNU es una coleccin de subrutinas diseadas para usarse en distintos sistemas operativos y arquitecturas. El objetivo de esta segunda
biblioteca es facilitar el desarrollo multi-plataforma de aplicaciones de software libre.
En los sistemas en los que se usan, estas
bibliotecas de C proporcionan y definen las
llamadas al sistema y otras funciones bsicas, y son utilizadas por casi todos los programas. Sobre todo, es muy usada en los sistemas GNU y en el kernel de Linux. Cuando hablamos de Linux como sistema operativo completo debemos referirnos a l como
Figura 3: GNU + Linux = GNU/Linux
GNU/Linux para reconocer que el sistema lo compone tanto el ncleo Linux como las bibliotecas de C y otras herramientas de
GNU que hacen posible Linux1 .
glibc y gnulib son muy portables y soportan gran cantidad de plataformas de hardware [5]. En los sistemas Linux se instalan normalmente con el nombre de libc6 y gnulib
respectivamente. No debe confundirse con GLib2 , otra biblioteca que proporciona estructuras de datos avanzadas como rboles, listas enlazadas, tablas hash, etc. y un entorno de
orientacin a objetos en C.
En estas prcticas utilizaremos la biblioteca glibc como implementacin de programa1
2

http://es.wikipedia.org/wiki/Controversia_por_la_denominaci%C3%B3n_GNU/Linux
http://library.gnome.org/devel/glib/

Programacin y Administracin de Sistemas 2011-2012

cin del API POSIX. Algunas distribuciones de GNU/Linux, como Debian o Ubuntu utilizan
una variante de la glibc llamada eglibc3 , pero a efectos de programacin no debera haber diferencias.

2.

Objetivos
Conocer algunas rutinas POSIX y su implementacin glibc.
Aprender a utilizar bibliotecas externas en nuestros programas.
Aprender cmo funcionan internamente algunas partes de GNU/Linux.
Mejorar la programacin viendo ejemplos hechos por los desarrolladores de las bibliotecas.
Aprender a comunicar aplicaciones en red y conocer brevemente la arquitectura ClienteServidor.

3.

Entrega de prcticas

Se pedir la entrega y defensa de algunos ejercicios resmenes que integren varios de los
conceptos y funciones estudiadas en clase. Las prcticas deben realizarse a nivel individual
y se utilizarn mecanismos para comprobar que se han realizado y entendido.

4.

Documentacin de POSIX y las bibliotecas

Documentacin POSIX.1-2008: Especificacin del estndar POSIX. Dependiendo de la parte que documente es ms o menos pedaggica4 .
Documentacin GNU C Library: Esta documentacin incluye muchos de los conceptos que
ya habis trabajado en asignaturas de introduccin a la programacin o de sistemas
operativos. Es una gua completa de programacin en el lenguaje C, pero sobre todo incluye muchas funciones que son esenciales para programar, tiles para ahorrar
tiempo trabajando o para garantizar la portabilidad del cdigo entre sistemas POSIX5 .

5.

Procesado de lnea de comandos tipo POSIX

5.1.

Introduccin y documentacin

Los parmetros que procesa un programa en sistemas POSIX deben seguir un estndar
de formato y respuesta esperada6 . Un resumen de lo definido en el estndar es lo siguiente:
3

http://www.eglibc.org/home
http://pubs.opengroup.org/onlinepubs/9699919799/
5
http://www.gnu.org/software/libc/manual/
6
12.1
Utility
Argument
Syntax,
http://pubs.opengroup.org/onlinepubs/9699919799/
basedefs/V1_chap12.html
4

6. Variables de entorno

Una opcin es un guin - seguido de un carcter alfanumrico, por ejemplo, -o.


Una opcin requiere un parmetro que debe aparecer inmediatamente despus de la
opcin, por ejemplo, para -o lo siguiente: -o parmetro o -oparmetro.
Las opciones que no requieren parmetros pueden agruparse detrs de un guin, por
ejemplo, -lst es equivalente a -t -l -s.
Las opciones puede aparecer en cualquier orden, as -lst es equivalente a -tls.
Las opciones pueden aparecer muchas veces.
El parmetro -- indica el fin de las opciones en cualquier caso.
La opcin - a menudo se indica para representar alguna entrada estndar.
La funcin getopt()7 del estndar ayuda a desarrollar el manejo de las opciones siguiendo las directrices POSIX.1-2008. getopt() est implementada en libc89 . Puedes ver
cdigo de ejemplo comentado en el fichero ejemplo-getopt.c. El fichero ejemplo-getoptlong.c
contiene un ejemplo de procesado de rdenes al estilo de GNU (por ejemplo, --help y -h
como rdenes compatibles). Este segundo ejemplo no lo veremos en clase.

5.2.

Ejercicios

Descarga el cdigo de ejemplo de getopt() de la documentacin de glibc10 . Lee el


cdigo, complalo, ejectalo para comprobar que admite las opciones de parmetros POSIX.
Trata de entender el cdigo y aade ms opciones (por ejemplo una sin parmetros y otra con
parmetros). Debes consultar la seccin Using the getopt function de la documentacin11
para saber cmo funciona getopt, qu valores espera y qu comportamiento tiene.

6.

Variables de entorno

6.1.

Introduccin y documentacin

Una variable de entorno es un objeto designado para contener informacin usada por
una o ms aplicaciones. La variables de entorno se asociacin a toda la mquina, pero tambin a usuarios individuales. Si utilizas bash, puedes consultar las variables de entorno de
tu sesin con el comando env. Tambin puedes consultar o modificar el valor de una variable de forma individual:
$ env
$ ...
$ echo $LANG
es_ES.UTF-8
$ export LANG=en_GB.UTF-8
7

http://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html
http://www.gnu.org/software/libc/manual/html_node/Getopt.html
9
Notas sobre portabilidad en http://www.gnu.org/software/gnulib/manual/gnulib.html#
getopt
10
http://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html
11
http://www.gnu.org/software/libc/manual/html_node/Using-Getopt.html
8

Programacin y Administracin de Sistemas 2011-2012

6.2.

Ejercicios

Utilizando la funcin getenv()12 , haz un programa que dependiendo del idioma de la


sesin de usuario, imprima un mensaje con su carpeta personal en castellano o en ingls.
Puedes ver cdigo de ejemplo en el fichero ejemplo-getenv.c.

7.
7.1.

Obtencin de informacin de un usuario/a


Introduccin y documentacin

En los sistemas operativos la base de datos de usuarios puede ser local y/o remota. Por
ejemplo, en GNU/Linux puedes ver los usuarios y grupos locales en los ficheros /etc/passwd
y /etc/group. Si los usuarios no son locales normalmente se encuentran en una mquina
remota a la que se accede por un protocolo especfico. Algunos ejemplos son el servicio de
informacin de red (NIS, Network Information Service) o el protocolo ligero de acceso a directorios (LDAP, Lightweight Directory Access Protocol). En la actualizad NIS apenas se usa y
LDAP es el estndar para autenticar usuarios tanto en sistemas Unix o GNU/Linux como
en sistemas Windows.
En el caso de GNU/Linux, la autenticacin de usuarios la realizan los mdulos de autenticacin PAM (Pluggable Authentication Module). PAM es un mecanismo de autenticacin
flexible que permite abstraer las aplicaciones del proceso de identificacin. La bsqueda de
su informacin asociada la realiza el servicio NSS (Name Service Switch), que provee una interfaz para configurar y acceder a diferentes bases de datos de cuentas de usuarios y claves
como /etc/passwd, /etc/group, /etc/hosts, LDAP, etc.
POSIX presenta una interfaz para el acceso a la informacin de usuarios que abstrae al
programador de dnde se encuentran los usuarios (en bases de datos locales y/o remotas,
con distintos formatos, etc.). Por ejemplo, la llamada getpwuid() devuelve una estructura
con informacin de un usuario. El sistema POSIX se encarga de intercambiar informacin
con NSS para conseguir la informacin del usuario. NSS leer ficheros en el disco duro o
realizar consultas a travs de la red para conseguir esa informacin.

7.2.

Ejercicios

Puedes ver las funciones y estructuras de acceso a la informacin de usuarios/as y grupos en los siguientes ficheros de cabecera: /usr/include/pwd.h /usr/include/grp.h.
La funcin getpwnam()13 permite obtener informacin de un usuario/a. Mira el programa
de ejemplo de getpwnam() y amplalo para utilizar getgrgid()14 para obtener el nombre
del grupo del usuario a travs del identificador del grupo. Puedes ver cdigo de ejemplo en
el fichero ejemplo-infousuario.c.
12

http://pubs.opengroup.org/onlinepubs/009604599/functions/getenv.html
http://pubs.opengroup.org/onlinepubs/009604599/functions/getpwnam.html
http://www.gnu.org/software/libc/manual/html_node/User-Database.html
14
http://www.gnu.org/software/libc/manual/html_node/Group-Database.html
13

9. Creacin de procesos Fork y Exec

8.

Ejercicio resumen 1 (0.5 punto)

Realizar un programa que obtenga e imprima la informacin de un usuario (todos los


campos de la estructura passwd) pasado por el parmetro -u. Si adems se le pasa la opcin
-g deber buscar e imprimir la informacin del grupo del usuario (nmero ID del grupo y
nombre).
Si se le pasa la opcin -e imprimir el mensaje en castellano, y la opcin -s hace que lo
imprima en ingls. Si no se le pasa ni -e ni -s se mirar la variable de entorno LANG para
mostrar la informacin. Por ejemplo, las siguientes llamadas seran vlidas:
#
#
$
#
#
$
#
#
$

Obtener la informacin de un usuario usando el idioma


configurado en LANG
infousuario -u i02samoj
Obtener la informacin de un usuario forzando el
idioma en castellano
infousuario -u i02samoj -e
Obtener la informacin de un usuario aadiendo la
informacin de su grupo principal e imprimiendo todo en ingls
infousuario -u i02samoj -s -g
El control de errores debe ser el siguiente:
Asegurar que se pasa el nombre del usuario (tienes un ejemplo de cmo controlar que
se pasa el parmetro de una opcin en el ejemplo-getopt.c).
Las opciones -e y -s no pueden activarse a la vez.

Sugerencia: empezar por el cdigo de ejemplo ejemplo-getopt.c. Primero debe procesarse la entrada de comandos para asegurarse que no falta ninguna opcin esencial (por
ejemplo el nombre de usuario). Despus debe ir la lgica del programa dependiendo de las
opciones que se hayan reconocido. Se pueden hacer funciones para simplificar la funcin
main. Por ejemplo, una funcin para imprimir la informacin del usuario en castellano/ingls a la que se le pase la estructura struct passwd y una opcin. Una sugerencia para el
esquema general puede ser:
1. Procesar opciones de entrada.
2. Usar la variable de entorno LANG si las flags de las opciones -e o -s estn a cero.
3. Llamar a una funcin que imprima la informacin de un usuario en ingls o castellano
con las opciones (login, grupo si/no, idioma).

9.
9.1.

Creacin de procesos Fork y Exec


Introduccin y documentacin

En general, en sistemas operativos y lenguajes de programacin, se llama bifurcacin o


fork a la creacin de un subproceso copia del proceso que llama a la funcin. El subproceso
creado, o proceso hijo, proviene del proceso originario, o proceso padre. Los procesos

Programacin y Administracin de Sistemas 2011-2012

pid=fork()

case 0:
// hijo
default:
// padre

Figura 4: Esquema de llamadas y procesos generados por fork() en el ejemplo.


resultantes son idnticos, salvo que tienen distinto nmero de proceso (PID)15 . En UNIX
otra forma de crear subprocesos es utilizar tuberas o pipes, las cules son esenciales para la
comunicacin inter-procesos, por ejemplo:
$ find . -name "*.c" -print | wc -l
En C se crea un subproceso con llamando a la funcin fork()16 . Tienes un pequeo
manual y mucho cdigo de ejemplo en [6]. Puedes ver un cdigo con muchos comentarios
en la entrada de Wikipedia17 . El nuevo proceso hereda varias propiedades del proceso padre
(variables de entorno, descriptores de ficheros, etc. ). En esta asignatura no entraremos en
qu sucede internamente a nivel del sistema operativo. Despus de una llamada exitosa a
fork habr dos copias del cdigo original ejecutndose a la vez. En el proceso original, el
valor devuelto de fork ser el identificador del proceso hijo. En cambio, en el proceso hijo
el valor devuelto por fork ser 0.

9.2.

Ejercicios y ejemplos

El listado siguiente (ejemplo-fork.c) es un ejemplo de uso de fork que controla qu


tipo de proceso es el que ejecuta el cdigo utilizando el valor devuelto por la funcin, as como otras funciones POSIX para obtener informacin de los procesos (puedes ver un esquema
de las subprocesos creados en la Figura 4):
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
pid_t rf;
rf = fork();
switch (rf)
15

http://www.gnu.org/software/libc/manual/html_node/Processes.html
http://pubs.opengroup.org/onlinepubs/9699919799/
17
http://es.wikipedia.org/wiki/Bifurcaci%C3%B3n_%28sistema_operativo%29
16

9. Creacin de procesos Fork y Exec

{
case -1:
printf ("No he podido crear el proceso hijo \n");
exit(-1);
case 0:
printf ("Soy el hijo, mi PID es %d y mi PPID es %d \n",
getpid(), getppid());
sleep (5);
break;
default:
printf ("Soy el padre, mi PID es %d y el PID de mi hijo es
%d \n", getpid(), rf);
sleep (10);
}
printf ("Final de ejecucin de %d \n", getpid());
exit (0);
}
Un ejemplo de llamada a este cdigo sera:
$ ./ejemplo-fork
Soy el padre, mi PID es 23455 y el PID de mi hijo es 23456
Soy el hijo, mi PID es 23456 y mi PPID es 23455
Final de ejecucin de 23456
Final de ejecucin de 23455
En este ejemplo el proceso padre no queda bloqueado esperando al hijo, prueba a poner
un valor menor de espera (sleep) para el padre que para el hijo:
$ ./ejemplo-fork
Soy el padre, mi PID es 23437 y el PID de mi hijo es 23438
Soy el hijo, mi PID es 23438 y mi PPID es 23437
Final de ejecucin de 23437
$ Final de ejecucin de 23438
Si quisiramos que el proceso padre esperase a que el proceso (o los procesos) hijos terminasen, debemos utilizar la funcin wait18 . El valor devuelto por la funcin wait es el
PID del proceso hijo que se est esperando que termine, si se le ha pasado un PID como
argumento. Si slo se le pasa &status, wait() espera a que terminen todos los procesos
hijos y devuelve el PID del ltimo proceso en terminar. Un ejemplo:
#include <unistd.h>
#include <sys/wait.h>
int main(){
pid_t pid;
int status, died;
18

www.gnu.org/software/libc/manual/html_node/Process-Completion.html

10

Programacin y Administracin de Sistemas 2011-2012

switch(pid=fork()){
case -1: printf("cant fork\n");
exit(-1);
case 0 : sleep(2); // cdigo que ejecuta el hijo
exit(3);
default: died= wait(&status); // cdigo que ejecuta el padre
}
}
En ocasiones puede interesar ejecutar un programa distinto, no diferentes partes de l, y
se quiere iniciar este segundo proceso diferente desde el programa principal. La familia de
funciones exec() permiten iniciar un programa dentro de otro programa. En lugar de crear
una copia del proceso, como fork(), exec() provoca el reemplazo total del programa
que llama a la funcin por el programa llamado. Por ese motivo se suele utilizar exec()
junto con fork(), de forma que sea un proceso hijo el que cree el nuevo proceso para que
el proceso padre no sea destruido. Podemos ver este mecanismo en el siguiente cdigo de
ejemplo:
#include
#include
#include
#include

<unistd.h>
<sys/wait.h>
<stdio.h>
<stdlib.h>

int main()
{
pid_t pid;
int status, died;
char *args[] = {"/bin/ls", "-r", "-t", "-l", (char *) 0 };
switch(pid=fork())
{
case -1:
printf("cant fork\n");
exit(-1);
case 0 :
printf("child\n"); // cdigo que ejecuta el hijo
execv("/bin/ls", args);
default:
died= wait(&status); // cdigo que ejecuta el padre
}
return(0);
}

11

10. Seales entre procesos

10.
10.1.

Seales entre procesos


Introduccin y documentacin

Las seales entre programas son interrupciones software que se generan para informar
a un proceso de la ocurrencia de un evento. Otras formas alternativas o complementarias de
comunicacin entre procesos son las tuberas POSIX (funciones popen y relacionadas) y las
las colas de mensajes POSIX o POSIX message queues (funciones mq_open, mq_send. . . ). Los
programas pueden disearse para capturar una o varias seales proporcionando una funcin que las maneje. Este tipo de funciones se llaman tcnicamente callbacks o retrollamadas.
Una callback es una referencia a un trozo de cdigo ejecutable, normalmente una funcin,
que se pasa como parmetro a otro cdigo. Esto permite, por ejemplo, que una capa de bajo
nivel del software llame a la subrutina o funcin definida en una capa superior (ver Figura
5, fuente Wikipedia19 ).

Application program
Main program

Callback function

calls

calls
Library function
Software library

Figura 5: Esquema del funcionamiento de las callbacks o retrollamadas.


Por ejemplo, cuando se apaga GNU/Linux, se enva la seal SIGTERM a todos los procesos, as los procesos pueden capturar esta seal y terminar de forma adecuada, por ejemplo
liberando recursos, cerrando ficheros abiertos, etc. La funcin signal20 permite asociar una
determinada funcin (a travs de un puntero a funcin) a una seal identificada por un entero (SIGTERM, SIGKILL, etc.).
#include <signal.h>
sighandler_t signal(int signum, sighandler_t handler);
...

10.2.

Ejercicios y ejemplos

El cdigo de ejemplo ejemplo-signals.c21 contiene ejemplos captura de seales POSIX enviadas a un programa. Recuerda que la funcin signal() no llama a ninguna funcin,
19

http://en.wikipedia.org/wiki/Callback_%28computer_science%29
http://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html
21
Fuente http://www.amparo.net/ce155/signals-ex.html
20

12

Programacin y Administracin de Sistemas 2011-2012

lo que hace es asociar una funcin del programador a eventos que se generan en el sistema,
esto es, pasar un puntero a una funcin.
$ ./ejemplo-signal
Cannot handle SIGKILL!
I caught the SIGHUP signal!
I caught the SIGTERM signal!
Terminado (killed)
# En otra terminal: obtener el PID del proceso
$ ps -e|grep signal
31188 pts/0
00:00:05 ejemplo-signal
$ kill -SIGHUP 31188
$ killall ejemplo-signal # mandamos seal SIGTERM
$ killall ejemplo-signal -9 # Forzamos parar el programa con
SIGKILL

11.
11.1.

sockets POSIX
Introduccin y conceptos bsicos

En esta seccin haremos una pequea introduccin a los sockets POSIX, una herramienta que permite desarrollar aplicaciones que se comuniquen entre s a travs de una red
utilizando diferentes protocolos o facilitando el desarrollo de otros protocolos sobre TCP/IP.
Como esta no es una asignatura especfica de redes, aprenderemos algunos conceptos y algoritmos bsicos para la comunicacin pero sin entrar en detalle del funcionamiento y de
todas las opciones disponibles. Si tienes duda sobre alguna funcin, hay un buen resumen
en castellano con los pasos y funciones para utilizar sockets en la web chuidiang.com [7],
nosotros usaremos algunas descripciones de este manual por ser muy sencillas y claras. A
continuacin daremos algunas definiciones.
Protocolo: En una red de ordenadores hay varios ordenadores que estn conectados entre si
por un medio fsico (cable, ondas inalmbricas, etc.) a travs del cul puede transmitirse informacin. Para que exista esta comunicacin debe haber un idioma o protocolo
comn entre los equipos. Hay muchsimos protocolos de comunicacin, entre los cuales el ms extendido es el TCP/IP. El ms extendido porque es el que se utiliza en
Internet.
socket: Un socket no es ms que un canal de comunicacin entre dos programas que
corren sobre ordenadores distintos o incluso en el mismo ordenador. Desde el punto
de vista de programacin, un socket no es ms que un fichero que se abre de una
manera especial. Una vez abierto se pueden escribir y leer datos de l con las habituales
funciones de read() y write() del lenguaje C. Existen bsicamente dos tipos de
canales de comunicacin o sockets, los orientados a conexin (por ejemplo TCP)
y los no orientados a conexin (por ejemplo UDP). Nosotros veremos un ejemplo de
funcionamiento de sockets orientados a la conexin.
arquitectura cliente-servidor: La arquitectura cliente-servidor es un modelo de aplicacin
distribuida en el que las tareas se reparten entre los proveedores de recursos o servicios,

13

11. sockets POSIX

llamados servidores, y los demandantes, llamados clientes. Por ejemplo, la World Wide
Web (WWW) se implementa con este modelo. El servidor es el programa que permanece
pasivo a la espera de que alguien solicite conexin con l, normalmente, para pedirle
algn dato. Cliente es el programa que solicita la conexin para, normalmente, pedir
datos al servidor.

11.2.

Algoritmo bsico Cliente-Servidor

La Figura 6 muestra el diagrama de flujo general de la comunicacin Cliente-Servidor


utilizando sockets.
Diagrama de ujo
de un socket TCP
implementando el modelo
Cliente-Servidor

Servidor
socket()

bind()

Cliente

listen()

socket()
accept()
connect()

send()

recv()

closeSocket()

El cliente enva datos y


el servidor los recive

El servidor enva datos


y el cliente los recive

El cliente manda un
mensaje para nalizar
la conexin

recv()

send()

recv()

closeSocket()

Figura 6: Diagrama de flujo de la implementacin del modelo Cliente-Servidor orientado a


la conexin con sockets POSIX.

14

Programacin y Administracin de Sistemas 2011-2012

11.3.

Pasos de programacin C en el lado Servidor

Con C en Unix/Linux, los pasos que debe seguir un programa servidor son los siguientes
[7]:
Apertura de un socket, mediante la funcin socket(). Esta funcin devuelve un descriptor de fichero normal, como puede devolverlo open() o fopen(). La funcin
socket() no hace absolutamente nada respecto a iniciar la comunicacin, salvo devolvernos y preparar un descriptor de fichero que el sistema posteriormente asociar
a una conexin en red.
Avisar al sistema operativo de que hemos abierto un socket y queremos que asocie
nuestro programa a dicho socket. Se consigue mediante la funcin bind(). El sistema todava no atender a las conexiones de clientes, simplemente anota que cuando
empiece a hacerlo, tendr que avisarnos a nosotros. Es en esta llamada cuando se debe
indicar el nmero de servicio (o puerto) al que se quiere atender.
Avisar al sistema de que comience a atender dicha conexin de red. Se consigue mediante la funcin listen(). A partir de este momento el sistema operativo anotar
la conexin de cualquier cliente para pasrnosla cuando se lo pidamos. Si llegan clientes ms rpido de lo que somos capaces de atenderlos, el sistema operativo hace una
cola con ellos y nos los ir pasando segn vayamos pidindolo.
Pedir y aceptar las conexiones de clientes al sistema operativo. Para ello hacemos una
llamada a la funcin accept(). Esta funcin le indica al sistema operativo que nos d
al siguiente cliente de la cola. Si no hay clientes se quedar bloqueada hasta que algn
cliente se conecte.
Escribir y recibir datos del cliente, por medio de las funciones write() y read(), que
son exactamente las mismas que usamos para escribir o leer de un fichero. Obviamente,
tanto cliente como servidor deben saber qu datos esperan recibir, qu datos deben
enviar y en qu formato, por ejemplo el protocolo HTTP y el formato HTML o XHTML.
Cierre de la comunicacin y del socket, por medio de la funcin close(), que es la
misma que sirve para cerrar un fichero.

11.4.

Pasos de programacin C en el lado Cliente

Nosotros no veremos la parte del cliente, ya que cualquier navegador web ser el cliente
de nuestro servidor. Los pasos que debe seguir un programa cliente son los siguientes [7]:
Apertura de un socket, como el servidor, por medio de la funcin socket().
Solicitar conexin con el servidor por medio de la funcin connect(). Dicha funcin
quedar bloqueada hasta que el servidor acepte nuestra conexin o bien si no hay
servidor en el sitio indicado, saldr dando un error. En esta llamada se debe facilitar la
direccin IP del servidor y el nmero de servicio que se desea.
Escribir y recibir datos del servidor por medio de las funciones write() y read().
Cerrar la comunicacin por medio de close().

12. Todo junto: un servidor web bsico en C

15

Figura 7: Ejemplo de ejecucin del servidor web con la llamada ejemplo-webserver -p


8080 -r htdocs

12.
12.1.

Todo junto: un servidor web bsico en C


Introduccin y cdigo

En esta seccin vamos a ver un ejemplo que combina muchas de las funciones POSIX
que hemos visto en las prcticas. Esta seccin la trabajaremos directamente sobre el cdigo
de ejemplo ejemplo-webserver.c. Este ejemplo es un cdigo ampliado descargado de
internet con algunas funciones auxiliares que se han aadido para facilitar los ejercicios.
Pregunta todas las dudas que tengas durante la explicacin del cdigo. El objetivo es tratar
de reconocer los pasos del modelo Cliente-Servidor de la Figura 6 a grandes rasgos y sin
perderse en los detalles, ya que no se pedir ninguna modificacin de las partes de cdigo
relativas a la comunicacin.. La Figura 8 muestra el funcionamiento general del cdigo del
servidor web combinando el esquema de la Figura 6 con fork() para poder atender varias
conexiones de manera simultnea.

16

Programacin y Administracin de Sistemas 2011-2012


Servidor

Diagrama de ujo
del ejemplo de
servidor web bsico

El socket creado por el proceso


principal debera ser cerrado
al nalizar el programa,
por ejemplo capturando las
seales SIGTERM, SIGINT...

socket()

startServer()

bind()

listen()

Cliente
La llamada a accept() crea un nuevo
socket para atender la conexin
que deber ser cerrado al nalizar
el intercambio de datos.

socket()

accept()

connect()

while(1) {
...
fork()
...
}

fork()
GET /hola.html HTTP/1.1
recv()

send()

respond()

HTTP/1.0 200 OK
....
Datos
send()

recv()

closeSocket()

El cliente manda un
mensaje para nalizar
la conexin

recv()

closeSocket()

Figura 8: Diagrama de flujo de la implementacin del modelo Cliente-Servidor orientado a


la conexin con sockets POSIX.

12.2.

Ejercicios

Arranca y para el servidor siguiendo la ayuda de la lnea de comandos. Prueba a conectarte a l a travs del navegador y prueba a cambiar las opciones. Si no sabes HTML, mira
los ficheros de ejemplo del directorio htdocs del paquete de prcticas.
Para arrancar el servidor, que escuche en el puerto 8080 y que utilice el directorio htdocs
como raz para servir ficheros web:
$ ./ejemplo-webserver -p 8080 -r htdocs
ahora visita la direccin http://localhost:8080/ y comprueba que puedes navegar por
las pginas alojadas en el servidor. En el navegador deberas obtener un resultado similar al
de la Figura 7. Puedes probar a ejecutar el servidor en ts.uco.es, en este caso la direccin

17

13. Ejercicio resumen 2 (1 punto)

sera http://ts.uco.es:8080/. Si esto lo hacis varias personas, tal vez tengis que
cambiar el puerto porque slo una aplicacin puede escuchar en un puerto, este mensaje
de error os indicara que ya hay una aplicacin asociada al puerto que pretendis usar:
$ ./ejemplo-webserver -p 8080 -r htdocs
$ socket() or bind(): Address already in use
Este mensaje de error puede obtenerse an cuando haya finalizado la ejecucin de programa que escucha el puerto. Aunque el documento es antiguo y la explicacin tal vez no
sea precisa, puedes leer una explicacin de por qu pasa esto en [8]

13.

Ejercicio resumen 2 (1 punto)

Para este ejercicio partiremos del cdigo ejemplo-webserver.c. El Makefile del paquete de prcticas ya incluye una regla para compilar el fichero webserverex.c. Ejercicios:
1. La funcin webServerLog() implementa un pequeo sistema de registro o log (no
ptimo, por supuesto). Esta funcin es similar a printf(). Utilizndola se pueden
registrar mensajes de inicio o parada del servidor o los accesos al servidor en el fichero
access.log y los errores en el fichero error.log. Por ejemplo, puedes hacer las
siguientes llamadas:
webServerLog(WS_LOG_ACCESS, \
"Servidor iniciado en el puerto %s", PORT);
webServerLog(WS_LOG_ERROR, "Error en la conexin");
No necesitas reemplazar todos los mensajes, pero si los ms significativos: cuando no
se puede iniciar el servidor por estar el puerto ocupado, el inicio o parada del servidor
y las peticiones HTTP que llegan al servidor.
2. Modifica el cdigo del servidor web para que tenga una nueva opcin -f. Cuando se
pase esta opcin, el servidor deber incluir una foto del Fary en todas las pginas web
que sirva. Una imagen se incluye en HTML con el cdigo
<img src="fichero.jpg" alt="Texto alternativo"> insertado entre las etiquetas <BODY> y </BODY>, que es donde va el contenido en si de una pgina HTML.

Figura 9: El Fary

18

Programacin y Administracin de Sistemas 2011-2012

Ten en cuenta que el navegador har una peticin por cada fichero .html, y otra(s) por
cada imagen (u otros datos) contenidos en la web. As, si una web tiene una imagen,
el navegador pedir primero el fichero .html con un GET /hola.html HTTP/1.1 y
cuando lo abra y detecte la etiqueta <img ...> har otra peticin GET /fichero.jpg
HTTP/1.1 para que el servidor le enve el fichero de la imagen22 . Aydate y modifica
si lo necesitas las funciones auxiliares strcasestr()23 y copyfile(). Acurdate de
actualizar la ayuda del programa.
3. Captura algunas llamadas al sistema (SIGTERM, SIGINT y SIGHUP) para gestionar el
fin del programa adecuadamente. Puedes asociar estas tres seales con la misma funcin de parar el servidor. Se deberan finalizar y cerrar adecuadamente las conexiones
y ficheros abiertos. Opcionalmente puedes hacer un script de bash que arranque y pare
el servidor ejecutando el servidor y envindole la seal SIGTERM respectivamente. Por
ejemplo, start-server.sh y stop-server.sh.
4. Captura la URL solicitada por el cliente. Si se pide la URL http://servidor:puerto/
infousuario/i02samoj el servidor debe generar una web con la informacin del
usuario. Con el cdigo del ejercicio resumen 1 y usando un fichero temporal no debera ser muy difcil.
Para el segundo ejercicio, una llamada similar a
$ ./ejemplo-webserver -p 8080 -r htdocs/ -f
debera producir un resultado similar en el navegador al de la Figura 10.

14.

Trabajo futuro

Algunas ideas que no ha dado tiempo a hacer:


Utilizar el patrn de diseo singleton para guardar la configuracin del programa.
Controlar la destruccin de subprocesos del servidor pasado un tiempo.
Comunicacin inter-procesos con diferentes alternativas (tuberas, POSIX MQ, etc.).
Capturar cmo ha muerto un proceso WEXITSTATUS, WTERMSIG...
Hacer que el servidor sirva cdigo generado con PHP (por ejemplo recogiendo la salida
de php ejemplo.php)
22

La peticin de estos ficheros auxiliares se hace al servidor que sirve la web, pero tambin se puede hacer a
otro si el fichero se encuentra en otro sitio web. Esto ocurre por ejemplo cuando se inserta un vdeo de youtube o
similares en una pgina.
23
En el cdigo del servidor web se proporciona la funcin strcasestr(cadena, subcadena) para facilitar uno de los ejercicios. Esta funcin busca una subcadena dentro de una cadena. Devuelve un 0 si no encuentra
la subcadena o la posicin de la subcadena si la encuentra, es decir, un valor mayor que cero.

14. Trabajo futuro

19

Figura 10: Ejemplo del resultado de la ejecucin del servidor web para implementar la opcin -f.

20

Programacin y Administracin de Sistemas 2011-2012

Referencias
[1] Wikipedia. Posix wikipedia, la enciclopedia libre, 2012. [Internet; descargado 12abril-2012]. Available from: http://es.wikipedia.org/w/index.php?title=
POSIX&oldid=53746603.
[2] The IEEE and The Open Group. Posix.1-2008 the open group base specifications issue 7,
2008. Available from: http://pubs.opengroup.org/onlinepubs/9699919799/.
[3] Proyecto GNU. Gnu c library, 2012.
software/libc/libc.html.

Available from: http://www.gnu.org/

[4] Brian W. Kernighan, Dennis Ritchie, and Dennis M. Ritchie. C Programming Language
(2nd Edition). Pearson Educacin, 2 edition, 1991.
[5] Wikipedia. Glibc wikipedia, la enciclopedia libre, 2012. [Internet; descargado 12abril-2012]. Available from: http://es.wikipedia.org/w/index.php?title=
Glibc&oldid=53229698.
[6] Tim Love. Fork and exec, 2008. Available from: http://www-h.eng.cam.ac.uk/
help/tpl/unix/fork.html.
[7] chuidiang.com. Programacin de sockets en c de unix/linux, 2007. Available from:
http://www.chuidiang.com/clinux/sockets/sockets_simp.php.
[8] Andrew Gierth Vic Metcalfe and other contributers. Programming UNIX Sockets in
C - Frequently Asked Questions. 4.2 Why dont my sockets close?, 1996. Available from: http://www.softlab.ntua.gr/facilities/documentation/unix/
unix-socket-faq/unix-socket-faq-4.html#ss4.2.
[9] Wikipedia. Dennis ritchie wikipedia, la enciclopedia libre, 2012. Available from: http:
//es.wikipedia.org/wiki/Dennis_Ritchie.

Das könnte Ihnen auch gefallen