Está en la página 1de 18

2

3
Programación de
sistemas LINUX
Guía de autoeducación

Ukranio Coronilla Contreras


Profesor de la Escuela Superior de Cómputo

Instituto Politécnico Nacional – México

4
5
Agradecimientos

A la institución que ha coadyuvado en gran medida a


consolidar la mayor riqueza de nuestro México actual, a
saber: el capital humano técnicamente preparado. Porque
no tarde me di perfecta cuenta de que no es importante lo
que se sabe, sino, que se hace con lo que se sabe. Mi
mayor agradecimiento por permitirme ser parte en esta
noble labor, de formar profesionistas.

Al Instituto Politécnico Nacional, mi reconocimiento por


coadyuvar en la creación de esta obra. Y sirva también
como muestra de su compromiso social, el de poner la
técnica al servicio de la patria.

6
7
Índice
Prólogo ………………………………………………………………………...9

1 Introducción a UNIX ………………………………………………………… 11

2 Paso de argumentos …………………………………………………………. 15

3 PID, UID y variables de ambiente …………………………………………. 18

4 Creación de procesos ………………………………………………………... 19

5 Tuberías ………………………………………………………………………. 23

6 Memoria compartida ………………………………………………………... 26

7 Semáforos …………………………………………………………………..... 30

8 Manejo de archivos ………………………………………………………..… 35

9 Servidor de dominio Internet tipo UDP …………………………………… 39

10 Cliente Internet tipo UDP ………………………………………………...... 45

11 Señales y temporización ……………………………………………………… 48

12 Hilos (Threads) ……………………………………………………………….. 55

13 Servidor y Cliente TCP ………………………………………………….….. 60

14 RPC ……………………………………………………………………..……. 65

15 Mapas de memoria ……………………………………………………..……. 70

16 Gráficos en UNIX con X11…………………………………………………… 73

ANEXO A UNIX Instalación y comandos básicos…………………………….... 78

ANEXO B Soluciones…………………………………………………………….. 81

BIBLIOGRAFÍA…………………………………………………………………….... 88

8
9
Prólogo
El Sistema operativo UNIX® es uno de los más usados en los ámbitos académico y comercial
debido a su fiabilidad, potencia y flexibilidad. En los últimos años su popularidad se ha
extendido debido a las versiones LINUX para computadoras personales. LINUX se dispone
de manera gratuita junto con una gran cantidad de utilidades, herramientas de programación
y de redes, además de un código fuente abierto. Su alta seguridad ante los ataques por red y
virus lo hace un sistema operativo robusto y estable. Una de las razones más importantes
para el éxito de LINUX es su naturaleza de código fuente abierta. Debido a que permite la
constante mejora y eliminación de errores, por parte de programadores en todo el mundo.

Para los desarrolladores, la interfaz de llamadas al sistema que brinda LINUX, provee las
herramientas necesarias para la construcción de aplicaciones a bajo nivel, con excelente
desempeño y uso mínimo de recursos. Metas todas de cualquier ingeniero dedicado a la
programación de sistemas.

El lenguaje de desarrollo utilizado a lo largo del texto es C dada la estrecha relación que
guarda con la interfaz nativa de los sistemas UNIX®. A pesar de existir diversas variantes de
UNIX® se ha optado por trabajar con LINUX, aunque se han tratado de utilizar solo las
llamadas que son parte del estándar POSIX, lo cual garantiza su funcionamiento en
cualquiera de sus clones. Es muy recomendable conocer los comandos básicos de UNIX ®
aunque se pueden ir aprendiendo sobre la marcha.

Este libro se ha estructurado para ser una guía en el proceso de auto enseñanza en la
programación de sistemas UNIX®. El único requisito son conocimientos previos de
programación en lenguaje C y de arquitectura de computadoras.

Se incluyen al inicio de cada capítulo programas en su forma más simple que ilustran el
concepto clave. Dichos programas se pueden ejecutar de inmediato para facilitar la
comprensión del “fenómeno”. Posteriormente se da una explicación sobre las líneas de
código utilizadas, así como una serie de preguntas y actividades de programación que
permiten al lector mejorar el entendimiento del mismo. La intención principal es que el lector
comprenda de manera rápida, a utilizar la interfaz que ofrece UNIX para comunicarse con el
hardware subyacente. De esta manera el programador puede ahorrar tiempo en la elaboración
de proyectos sobre esta plataforma.

Como es el caso de cualquier texto, este también es susceptible de presentar errores.


Agradezco de antemano su enorme ayuda al hacérmelo saber, por medio de la editorial o del
correo electrónico: ukraniocc@yahoo.com
10
11
1

1 Introducción a UNIX
El sistema operativo UNIX así como sus clones derivados (LINUX, Mac OS,
MINIX, IRIX, etc.) mantienen ciertas características que lo han hecho exitoso
respecto a otros sistemas operativos, tanto en el campo educativo como en el
comercial. Con el objeto de tener una mejor comprensión de las funciones que
se verán a lo largo del texto daremos una explicación general del modo en que
opera UNIX.

El sistema operativo es el software que se instala en un área de memoria dentro


de cualquier sistema de cómputo. Dicho sistema de cómputo debe contar al
menos con una unidad de procesamiento (CPU), pero también puede constar
de varias unidades de procesamiento que podrían trabajar en paralelo. El
sistema operativo se encarga de administrar los recursos del sistema de
cómputo así como permitir al usuario interactuar con el hardware mediante una
interfaz. Para los usuarios finales la interfaz puede ser gráfica (con ventanas y
un apuntador que se controla con el mouse) o en modo texto la cual consiste en
un intérprete de comandos (Shell). Para el programador la interfaz consiste en
un conjunto de funciones conocidas como llamadas al sistema. Estas pueden
incorporarse a los programas y permiten acceder a los recursos de hardware. El
propósito del presente texto es precisamente mostrar el uso de dichas llamadas
al sistema, y por consiguiente utilizar el hardware del sistema de cómputo en
las aplicaciones de software que desarrolle el programador. Cabe aclarar que
las llamadas al sistema aquí vistas son parte de un estándar definido por IEEE
conocido como POSIX (Portable Operating System Interface, la X viene de
UNIX). Un diagrama simple de esta interacción se muestra en la figura 1-1.

Figura 1-1
Interfaz del SO
para el
programador y
el usuario.

12
Como programador es muy importante que conozca y sepa usar la interfaz de
usuario para UNIX, es decir el conjunto de comandos que acepta el Shell y
permiten el manejo y administración del sistema. Una guía para este
aprendizaje se puede encontrar en el apéndice del texto.

UNIX es un sistema operativo multiusuario, lo cual significa que dos o más


usuarios pueden trabajar al mismo tiempo, y en sesiones distintas sobre un
mismo sistema de cómputo. Para este propósito se cuenta con una gran
cantidad de utilidades. Esta característica permite a varios programadores,
editar y compilar proyectos complejos sobre el mismo sistema de cómputo.
Un esquema típico se muestra en la figura 1-2 donde se tiene un sistema
compartido de varias terminales tontas (teclado y pantalla) conectadas a una
unidad de procesamiento central con varios procesadores.

Figura 1-2
Sistema
multiusuario.

También UNIX es un sistema operativo multiproceso, es decir que puede


ejecutar dos o más programas de manera simultánea. Por ejemplo podría
visualizarse un video mp4 y al mismo tiempo estarse reproduciendo una
canción almacenada en mp3. El multiprocesamiento se lleva a cabo mediante
la ejecución concurrente de los programas.

Dado que una CPU (Central Processing Unit) solo puede ejecutar una
operación aritmética en un instante dado. Para poder ejecutar dos programas,
es necesario que dichos programas compartan el CPU. De modo que cada
programa utiliza el CPU unos cuantos milisegundos (proceso en ejecución)
mientras el otro programa espera (proceso en estado de listo).

Como en general existen muchos procesos ejecutándose concurrentemente


(incluyendo las líneas de código del mismo sistema operativo), existe un
modulo del sistema operativo conocido como planificador (scheduler),
encargado de ceder el CPU a cada programa durante un intervalo constante de
tiempo conocido como cuanto. También determina quién es el siguiente
programa que puede usar el CPU en base a un algoritmo de calendarización.

Además de los estados de listo y en ejecución existe el estado de bloqueado.


Un proceso se encuentra en estado de bloqueado cuando no está haciendo uso
del procesador y además está esperando información proveniente de un
13
dispositivo o de otro proceso. Por ejemplo si un proceso requiere leer un
archivo del disco duro, es necesario que espere mucho tiempo (la lectura del
disco duro ocupa varios milisegundos). En este caso se pone al proceso en
estado de bloqueado y el planificador le cede el CPU a cualquier otro proceso
que se encuentre en estado de listo. Al llegar los datos provenientes del disco
duro se interrumpe al sistema operativo y este cambia el estado del proceso de
bloqueado a listo. Un diagrama de estados de los procesos se muestra en la
figura 1-3, así como las transiciones posibles entre ellos.

Figura 1-3
Estados de los
procesos y
transiciones
posibles.

El código más importante de un sistema operativo UNIX se conoce como


núcleo (kernel). Este es el encargado de permitir o impedir a los programas el
acceso al hardware. Cualquier programa que inicia su ejecución se encuentra
en el modo usuario. Si dicho programa desea manipular el hardware (por
ejemplo leer archivos del disco duro o leer la información proveniente de la
tarjeta de red) será necesario incluir la llamada al sistema correspondiente.
Esta llamada al sistema se ejecutará en modo kernel y es el código del kernel
quien permitirá o no, el acceso al hardware del que se trate. Este control es
necesario por la seguridad del sistema de cómputo, sobre todo considerando
que existen muchos usuarios dentro del mismo y la información de cada uno
de ellos, así como la exclusividad en el uso de los recursos (CPU, RAM,
archivos, dispositivos de E/S) es totalmente necesaria.

En la figura 1-4 podemos observar un gráfico del uso de CPU por parte de
procesos de usuario y del sistema operativo, así como los conceptos
anteriormente explicados.
14
Figura 1-4
Concurrencia de
procesos de
usuario y del
sistema
operativo.

La implementación de seguridad en los sistemas UNIX implica que exista un


control en el acceso de los usuarios al sistema. También la existencia de
permisos de acceso a los archivos, los cuales se dividen en tres categorías:
permisos de usuario, permisos de grupo y permisos para el resto de usuarios.
Estos atributos junto con algunos mas como tamaño, fecha de creación,
nombre, grupo, etc., se utilizan también para todos los dispositivos en el
sistema. Por esta razón podemos decir que en los sistemas UNIX todo se
representa como un archivo. Ganándose con esta generalización mayor
sencillez y una interfaz de llamadas al sistema pequeña en comparación con la
que ofrecen otros sistemas operativos.

La capacidad de multiprocesamiento tiene amplios beneficios para los


programadores de sistemas. Uno de ellos es que en lugar de tener un solo
programa grande, se pueden tener varios programas pequeños que interactúen
entre sí. Esto puede disminuir de manera drástica la complejidad de un
proyecto y por consiguiente hacerlo menos propenso a errores. También
fomenta la modularidad y flexibilidad así como la reutilización de código. En
consecuencia se puede elaborar código más robusto y estable.

15
1

2 Paso de argumentos

Introducción
Cuando se desarrolla un programa bajo un sistema operativo basado en UNIX ®
como es el caso de LINUX, se debe tener en consideración que se estará en un
ambiente multiproceso. Esto significa que en un momento dado, se estará
ejecutando nuestro programa de manera concurrente (o paralela en el caso de
que el sistema de computo cuente con más de un procesador) con muchos otros
programas. Inclusive podrían estarse ejecutando varias instancias de nuestro
programa.

De modo que es importante para el programador que sus programas no


interfieran con otros programas en el momento de estar haciendo uso
simultáneo de un recurso. Dicho recurso puede ser memoria, algún archivo en
disco, o inclusive el teclado.

Ejemplo práctico
Introduzca en un archivo con ayuda de un editor como vi, pico, o alguno otro de
su preferencia, el programa 2-1 y guárdelo como programa2-1.c

Programa 2-1 #include <stdio.h>


Imprime #include <stdlib.h>
argumentos y
opciones.
int main(int argc, char *argv[])
{
int tokens;

for(tokens = 0; tokens < argc; tokens++) {


if(argv[tokens][0] == '-')
printf("opción: %s\n", argv[tokens]+1);
else
printf("argumento %d: %s\n", tokens, argv[tokens]);
}
exit(0);
}

16
Posteriormente construya el programa ejecutable con la siguiente instrucción en
la línea de comandos:

gcc programa2-1.c –o programa2-1

gcc es el compilador más utilizado en los sistemas UNIX, la opción –o indica al


compilador que el nombre del archivo ejecutable será el que se especifica a
continuación (en este caso programa2-1). Se recomienda darle el mismo
nombre al ejecutable que al código fuente para evitar confusiones. Es también
común dejar al archivo ejecutable sin una extensión.

Pregunta 2-1 Quite la extensión .c al programa e intente compilar, posteriormente cambie la


extensión por otra de su agrado. ¿Qué sucede?

Se puede ver el manual del compilador gcc mediante el comando de ayuda man.
Solo debemos teclear en la línea de comandos:

man gcc

Este comando es muy útil para ver el manual de cualquier llamada al sistema,
función o comando.

Ejecute el programa anteponiendo “./” al nombre del programa ejecutable.

./programa2-1

Agregue otras palabras en la línea de comandos, estas se conocen como


argumentos del programa. Un argumento que inicia con el signo menos “-” se
conoce como opción del programa.

Como podrá observar nuestro programa detecta los argumentos y/o opciones
que se le envían en la línea de comandos.

Descripción del funcionamiento


En su forma general un programa que se elabora en LINUX puede tener el
siguiente prototipo para su función principal:

int main(int argc, char *argv[])

Esta función devuelve un entero y recibe dos argumentos, el número entero


que devuelve es capturado por el sistema operativo. De modo que el sistema
operativo puede saber cuál es el estado de terminación del programa.

17
Por convención un programa que termina de manera normal debe devolver un
cero, lo cual se logra con la instrucción:

exit(0);

En el caso de que exista un fallo se recomienda devolver un valor negativo.

El sistema operativo a través del intérprete de comandos (shell), puede enviarle


información a nuestro programa cuando inicia. Esto se logra con ayuda de los
parámetros en la función principal. El sistema operativo va a colocar en la
variable argc el número de parámetros que introduzca el usuario en la línea
de comandos. La variable argv almacena un arreglo de cadenas de caracteres,
donde cada una de las cadenas contiene un argumento, comenzando por el
nombre del programa el cual se almacena en argv[0], el siguiente
argumento en argv[1] y así sucesivamente. La última cadena en el arreglo
tendrá siempre un apuntador a NULL. Y como es normal en C, cada cadena va
a terminar con el carácter fin de cadena '\0'.

Ejercicio 2-1 Suponga que no se dispone del argumento argc en la función principal, de
modo que no se conoce el numero de argumentos que el usuario introdujo en la
línea de comandos. Modifique el programa 2-1 para que realice el mismo
trabajo sin utilizar argc.

Ejercicio 2-2 Modifique el programa 2-1 para que imprima también, el número de caracteres
que conforma a cada uno de los argumentos.

Para que un programa pueda ejecutarse en segundo plano concurrentemente


con otros, o para conectar la salida de un proceso con la entrada de otro, es
necesario pasarle al programa toda la información que necesite, a través de la
línea de comandos. Esta información se transmite en forma de opciones o con
argumentos. De otro modo tendrían que programarse menús interactivos, que
evitarían a otros procesos compartir el teclado y la pantalla.

18