Procesos. Aspectos básicos

Documentos relacionados
Redes de Computadores: Relación de problemas 1. Sockets

-> Todo socket viene definido por dos características fundamentales:

Sockets (TCP) Tema 2.- Nivel de aplicación en Internet

Introducción a la programación con sockets en C

Redes de Computadores Nivel de Aplicación: Programación con sockets I

UNIVERSIDAD DE CANTABRIA DEPARTAMENTO DE INGENIERÍA DE COMUNICACIONES GRUPO DE INGENIERÍA TELEMÁTICA

Estructuras y funciones de programación de sockets.

Arquitecturas Cliente/Servidor

Migrando aplicaciones a IPv6

Mecanismos IPC: sockets

Sistemas Operativos: Programación de Sistemas. Curso Oscar Déniz Suárez Alexis Quesada Arencibia Francisco J.

Sockets: funcionamiento y programación. Sockets tipo UNIX. MSc. Ivan A. Escobar

Desarrollo de Aplicativos con winsockets

Problemas de Redes de Computadores. Ingeniería Técnica en Informática de Gestión Conjunto de problemas 1

Problemas de Redes de Computadores. Conjunto de problemas 1

Sistemas Operativos Distribuidos

Estructuras y funciones de programación de sockets.

sockets Flujo (SOCK_STREAM) Comunicación bidireccional Confiable (entrega garantizada) Información ordenada en el destino Datagrama (SOCK_DGRAM)

Sistemas Operativos Practica 1: procesos y concurrencia.

Introducción a Sockets en Linux

UNIVERSIDAD AUTÓNOMA DE BAJA CALIFORNIA FACULTAD DE CIENCIAS PRACTICA DE PROCESOS HERRAMIENTAS

Introducción de Sockets en C.

Sockets (UDP) Tema 2.- Nivel de aplicación en Internet

COMUNICACIÓN ENTRE PROCESOS SOCKETS

Qué es un socket? Dominios de comunicación. Tipos de sockets en el dominio AF_INET. Sockets Stream. Sockets Datagram. Sockets Raw

Sistemas Operativos: Programación de Sistemas. Curso Oscar Déniz Suárez Alexis Quesada Arencibia Francisco J.

TEMA 3. CONCEPTOS FUNDAMENTALES DEL NIVEL DEL SISTEMA OPERATIVO. Definición y objetivos de un S.O

Sistemas Operativos I. Enxeñería Informática. Curso 2007/08. Práctica 2: Concurrencia de procesos: Productores/Consumidores.

Características de un lenguaje ideal para robótica

ARQUITECTURA DE REDES Laboratorio

ARQUITECTURA DE REDES Laboratorio PRÁCTICA 2: MANUAL DE SOCKETS EN C. Grado en Ingeniería Informática Curso 2014/15

Mecanismos IPC System V

Procesos e Hilos en C

Diseño de aplicaciones distribuidas ÍNDICE

IPC SYSTEM V. Técnicas Digitales III Ing. Gustavo Nudelman Universidad Tecnológica Nacional - Facultad Regional Buenos Aires

Universidad Simón Bolívar Departamento de Computación y Tecnología de la Información Curso de Redes I CI-4815 Trimestre Septiembre Diciembre 2013

PRÁCTICA 2: Cliente-servidor UDP

Sockets. Los sockets son un mecanismo de comunicación entre procesos que se utiliza en Internet.

Programación C/S Básica

Ingeniería Técnica de Telecomunicación, esp. Telemática Universidad de Jaén

Redes (IS20) Ingeniería Técnica en Informática de Sistemas - (2º Curso)

Elementos de un programa en C

Programación con Sockets

Sistema Cliente Servidor Con Sockets

Tema 4: Sockets: Un interfaz con TCP/IP

DESARROLLO DE APLICACIONES DISTRIBUIDAS. SOCKETS en UNIX

Sockets Básicos. Sockets Básicos

Sistemas operativos. Hasta ahora hemos visto. Relación programa-sistema operativo Gestión de memoria

Adaptación de aplicaciones a IPv6

Sistemas Operativos Práctica 3

- Bajo que condiciones el algoritmo de planifiación de procesos FIFO (FCFS) resultaría en el tiempo de respuesta promedio más pequeño?

Tema 13: Apuntadores en C

Sockets Básicos. APIS para acceso a TCP/IP. APIS para acceso a TCP/IP. APIS para acceso a TCP/IP. APIS para acceso a TCP/IP. Temas a tratar...

Redes de Computadores Más sobre TCP. Área de Ingeniería Telemática Dpto. Automática y Computación

Clase de Sockets en lenguaje C. Prof. Ricardo González

Usando el Sistema Operativo

Capítulo 3: Procesos. n Concepto de Proceso. n Despacho (calendarización) de Procesos. n Operaciones en Procesos. n Procesos en cooperación

Paradigma de paso de mensajes

Escuela Politécnica Superior de Elche

TimeOut RTT medido 1 5 seg. 2*5= ,7 3 TimeOut 3 TimeOut 3 0, ,35 5 0,44

Programación de sockets

TEMA 7: Ficheros. TEMA 7: Ficheros Concepto de fichero

TELEPROCESO Y SISTEMAS DISTRIBUIDOS

Práctica 5: Implementación en C++ de sistemas cliente/servidor basados en comunicación

Análisis Experimental de la Transmisión de Datos

Bibliografía [COM00] Internetworking with TCP/IP, vol. 3, Cap. 2 y del 7 al 15.

LEER Y ESCRIBIR ARCHIVOS DE TEXTO CON PHP. FUNCIONES FOPEN (MODOS), FGETS, FPUTS, FCLOSE Y FEOF. EJEMPLOS (CU00836B)

APUNTADORES. Un apuntador es un objeto que apunta a otro objeto. Es decir, una variable cuyo valor es la dirección de memoria de otra variable.

Programación con sockets

ARQUITECTURA DE REDES Laboratorio

Nivel de Transporte en Internet

SOCKET S. Alberto Castro Rojas

07 << Acceso en exclusiva al recurso compartido >>

Tema 5 El Modelo Cliente-Servidor

Todo programa en 'C' consta de una o más funciones, una de las cuales se llama main.

IMPLEMENTACIÓN DE APLICACIONES DE SEGURIDAD CON OPENSSL

CUESTIONARIO PARA EL PROTOCOLO TCP/IP PREGUNTAS

Administración de redes en GNU/Linux

Computación de Alta Performance Curso 2009 PROGRAMACIÓN PARALELA EN LENGUAJE C

Lo guardamos como prog.c, lo compilamos y lo ejecutamos en la máquina tlm14 obteniendo el siguiente resultado:

Programación. Test Autoevaluación Tema 3

Programación de aplicaciones distribuidas usando sockets

Manipulación de procesos

Seguridad en el Sistema de Archivos. Dr. Alonso Ramírez Manzanares 23-Nov-2010

Práctica 1: sockets en Python

Modem IBM Compatible. IBM Compatible. Ethernet IBM AS/400. Laser printer. Workstation. Mac II. El Interfaz. Socket. versión perliminar

SOCKETS en Linux. Lic. Leonardo de - Matteis. Departamento de Ciencias e Ingeniería de la Computación Universidad Nacional del Sur 2011

Arquitectura de Redes y Servicios de Telecomunicación

Curso de Programación en C. Licenciatura, FCQeI. APUNTADORES.

Apuntadores (Punteros)

Bloque III: El nivel de transporte. Tema 6: Conexiones TCP

Programación estructurada (Introducción a lenguaje C)

Sistemas Operativos. Contents. Ezequiel Postan. Docentes. Guido Macchi. Esteban Ruiz. Federico Bergero. Guillermo Grimgblat

SOLUCION EXAMEN junio 2006

Tema ADQUISICIÓN Y TRATAMIENTO DE DATOS. Departamento de Ciencias de la Computación e IA. Subprogramas en C

SISTEMAS DE COMUNICACIONES DE DATOS

Sistemas distribuidos

DESARROLLO DE FUNCIONES EN EL SISTEMA INFORMÁTICO EJEMPLO DE CUESTIONES BÁSICAS A CONOCER:

Ingeniería Informática. Curso 3º. Sistemas Operativos Examen Final. TEORIA. 4 de Septiembre de 2009

Introducción a C++ y Code::Blocks

Transcripción:

Procesos Aspectos básicos 1. Atributos de un proceso 2. Tabla de procesos y área de usuario 3. Planificadores 4. Comandos a. ipcs b. ipcrm 5. Creación procesos 6. Llamadas al sistema. 7. Como manipular proceso a. Comunicación usando archivos b. Pipe c. Memoria compartida d. FIFO e. Socket 8. Procesos y señales.(tinaco y temporizador) Sincronización entre procesos 1. Semáforos(volumen) Ejemplo procesos 1. FIFO (lotería) 2. Memoria compartida(mínimos) 3. Colas de mensajes(simulación cajas) 4. Socket(cajeros)

Procesos Atributos de proceso Qué es exactamente un proceso? Un proceso es una instancia de un programa en ejecución y también la unidad básica de planificación de Linux. Básicamente tres son los estados de un proceso Estados 1. En ejecución Utiliza la CPU en el instante dado 2. Listo Ejecutable, se detiene en forma temporal para que se ejecute otro proceso 3. Bloqueado No se puede ejecutar debido a la ocurrencia de algún evento externo La transición de los estados de un proceso se lleva de la siguiente manera: 1. El proceso se bloquea en espera de datos 2. El planificador elije otro proceso 3. El planificador elige este proceso 4. Los datos están disponibles

Planificadores

Comando ipcs Cuando se trabaja con procesos y los mecanismos de comunicación entre ellos son importantes y para verificar la correcta comunicación el comando ipcs es de gran ayuda, a través de este comando se puede verificar los semáforos, memoria compartida y cola de mensajes. Para verificar el comando y sus acciones tecleamos #ipcs -h Si solo se teclea solo ipcs proporciona estado de los segmentos de memoria compartida, semáforos y cola de mensajes.

Comando ipcrm Al trabajar con mecanismo de tipo FIFO es importante conocer el comando ipcrm que tiene como tareas borrar mensajes, semáforos o indicadores de memoria compartida Su sintaxis se es la siguiente: Donde: Opción Acción -m shmid Borra el segmento de memoria compartida con identificador shmid -q msgid Borra la cola de mensaje don identificador msgid -s semid Borra el semáforo con identificador semid -M shmkey Borra la memoria compartida, que tiene como llave shmkey -Q msqkey Borra la cola de mensaje, creada con la llave msqkey -S semkey Borra el semáforo, creado con la llave semkey Ejemplo: Para ejemplificar más crearemos dos colas de mensajes

Verificamos su creación Y a continuación las eliminaremos desde la terminal y verificamos el estado.

Creación de un proceso (fork) Para la creación de un nuevo proceso se utiliza una llamada al sistema fork, la cual crea un nuevo proceso. El nuevo proceso, o proceso hijo será una copia del proceso que llama, o proceso padre. Su sintaxis de fork es: \beginverbatim #include <unistd.h> pid_t fork( ); \endverbatim la forma de invocarla es pid=fork(). La llamada a fork hace que el proceso actual se duplique. A la ejecución de fork, los dos procesos tiene una copia idéntica del contexto del nivel de usuario en otras palabra se podría decir que todo lo que se encuentra antes de fork se hereda mas no implica que su variables sean compartidas entre procesos, cabe mencionar que para realizar esta tarea existes otro mecanismos de comunicación como por ejemplo memoria compartida, además sus identificadores de procesos(pid) son diferentes, el proceso padre toma el valor del PID del proceso hijo y para el proceso hijo toma el valor 0, El proceso 0, creado por el núcleo cuando arranca el sistema, es el único que no se crea con una llamada a fork. Figura1

Si la llamada a fork falla, devolverá el valor -1, (ver figura 1) Cuando llamamos a fork, el núcleo realiza las siguientes operaciones: Busca una entrada libre en la tabla de procesos y la reserva para el proceso hijo. Asigna un identificador de proceso PID para el proceso hijo. Este número es único e invariable durante toda la vida del proceso y es la clave para poder controlar desde otro proceso. Realiza una copia del contexto del nivel de usuario del proceso padre para el proceso hijo. Las secciones que deben ser compartidas, como el código o las zonas de memoria compartida, no se copia, sino que se incrementan los contadores que indican cuántos procesos comparten esa zonas. Las tablas de control de fichero locales al proceso -como pueden ser la tabla de descriptores de archivos- también se copian del proceso padre al proceso hijo, ya que forman parte del contexto del nivel usuario. En las tablas globales del núcleo - tabla de ficheros y tabla de inodes- se incrementan los contadores que indican cuántos procesos tienen abiertos esos ficheros. Rertorna el proceso padre el PID del proceso hijo, y al proceso hijo le devuelve el valor 0. Cuando se hace programación concurrente con procesos o hilos dos aspectos son muy importantes para un correcto funcionamiento como son: sincronización y comunicación. Terminación de procesos (exit y wait) Existen múltiples mecanismo de sincronización de procesos como son: semáforos, monitores, variables de condición y mutex, ya que es uno de los problemas más difíciles cuando se hace programación concurrente, los más sencillos son usando la llamada al sistema sleep o exit y wait, no son los mecanismos más recomendados.

exit Una situación muy típica en programación concurrente es que el proceso padre espere a la terminación del proceso hijo antes de terminar su ejecución. Un ejemplo de esta situación es la forma de operar de los intérpretes de órdenes. Cuando escribimos una orden, el intérprete arranca un proceso para ejecutarla y no devuelve el control hasta que no se ha ejecutado completamente. Naturalmente, esto no se aplica cuando la orden se ejecuta en segundo plano. Para sincronizar los procesos padre e hijo se emplean las llamadas exit" y \verb"wait". La declaración de \verb"exit" es la siguiente: \beginverbatim #include <stdio.h> void exit(int status); \endverbatim Esta llamada termina la ejecución de un proceso y le devuelve el valor de \verb"status" al sistema.\\ La llamada exit tien además las siguientes consecuencias: \beginitemize \item Las funciones registradas por \verb"atexit" son invocadas en orden inverso a como fueron resgistradas. \verb"atexit" permite indicarle al sistemas las acciones que se deben ejecutar al producirse la terminación de un proceso. \item El contexto del proceso es descargado de memoria, lo que implica que la tabla de descriptores de fichero es cerrada y sus ficheros asociados cerrados, si no quedan más procesos que los que tengan abiertos. \item Si el proceso padre está ejecutando una llamada a \verb"wait", se le notifica la terminación de su proceso hijo y se le envia 8 bits menos significativos de status. Con esta información, el proceso padre puede saber en qué condiciones ha terminado el proceso hijo. \item Si el proceso padre no está ejecutando una llamada a \verb"wait", el proceso hijo se transforma en un proceso \textcolorrojozombi. Un proceso

Llamadas al sistema Suponiendo que existe una archivo llamado "suma" o en caso contrario se crear usando #vi suma o usando un editor grafico, y está organizado de la siguiente manera: //proceso5.c #include <stdio.h> #include <wait.h> #include <sys/types.h> #include <unistd.h> #include <errno.h> #include <stdlib.h> #define n 6 static char *cmd[]="who","ls","date","ps","uname"; int j,i,pid,status,proc; int buf; FILE *fp; int process_fork(int nproc) int i; for(i=1; i<=nproc-1;i++) if(fork()==0) return(i); return(0); main() j=rand()%5; /* utilizado por el proceso uno*/ pid=process_fork(n); switch(pid) case 0: printf("estoy en proceso"); for(i=1;i<=n;i++) wait(&i); fprintf(stdout,"\n\n padre con ID=%d \n\n",getpid()); exit(1); case 1: fprintf(stdout,"\n proceso 1 con ID=%d \n\n",getpid()); execlp(cmd[j],cmd[j],0); exit(0); case 2: fprintf(stdout,"\n proceso 2 con ID=%d \n\n",getpid());

system("sort -n suma"); exit(0); case 3: fprintf(stdout,"\n proceso 3 con ID=%d \n\n",getpid()); execlp("sort","sort","-n","suma",0); exit(0); case 4: fprintf(stdout,"\n proceso 4 con ID=%d \n\n",getpid()); if((fp=fopen("suma","r"))==null) printf("error al abri el archivo"); exit(0); else printf("buscando archivo \n"); while(!feof(fp)) fscanf(fp,"%d",&buf); printf("%d \n",buf); fclose(fp); exit(0); case 5: fprintf(stdout,"\n proceso 5 con ID=%d \n\n",getpid()); if((fp=fopen("suma","a"))==null) printf("error al abrir el archivo/escritura"); exit(0); else printf("escribiendo archivo \n"); fprintf(fp,"%d\n",2000); fclose(fp); exit(0); default: printf("no hay tal comando \n"); exit(0); wait(&status);

COMUNICACIÓN ENTRE PROCESOS En cuanto a la comunicación existen varios mecanismos de comunicación. A continuación se plantea una forma simple de comunicación, la cual consiste en utilizar un archivo para comunicar procesos Ejemplo: se tiene un conjunto de datos A=ai ai R 0 i 99, y se generan cuatro procesos(p1,p2,p3,p4) y el proceso padre(p0), cada hijo con una rebanada de 25 datos A1= ai 0 i 24 P1=min(A1) A2= ai 25 i 49 P2=min(A2) A3= ai 50 i 74 P3=min(A3) A4= ai 75 i 99 P4=min(A4) P0=min P1,P2, P3,P4 #include <stdio.h> #include <string.h> #include <wait.h> #include <sys/types.h> #include <unistd.h> #include <errno.h> #include <stdlib.h> int j,i,pid,status,proc,min=100,imin; int buf; FILE *fp; int cont=0,a[100]; char s2[20]; int process_fork(int nproc) int i; for(i=1;i<=nproc-1;i++) if(fork()==0) return(i); return(0); main() strcpy(s2,"minimo.txt");

fp= fopen (s2,"w+"); printf("valores del vector a[100]\n"); for(i=0;i<100;i++) a[i]=rand()%100; printf("%d ",a[i]); if(((cont+1)%25)==0)printf("\n"); cont++; printf("\n\n"); pid=process_fork(5); switch(pid) case 0: for(i=1;i<5;i++) wait(&i); printf("\n"); fp= fopen (s2,"r+"); while(!feof(fp)) fscanf(fp,"%d",&j); printf("** %d ** ",j); if(min>j) min=j; fclose(fp); printf("\n padre ID=%d valor minimo total %d\n",getpid(),min); remove(s2); exit(0); case 1: printf("\n"); min = a[0]; imin = 0; for (i=0; i<=24; i++) if (a[i]<min) min = a[i]; printf("%d ",a[i]); printf("\n minimo parcial %d proceso 1 ID %d \n", min,getpid()); fprintf(fp,"%d\n",min); fclose ( fp ); exit(0); case 2: printf("\n"); min = a[25]; imin = 0; for (i=25; i<=49; i++) if (a[i]<min) min = a[i]; printf("%d ",a[i]); printf("\nminimo parcial %d proceso 2 ID %d \n", min,getpid());

fprintf(fp, "%d\n",min); fclose ( fp ); exit(0); case 3: printf("\n"); min = a[50]; imin = 0; for (i=50; i<=74; i++) if (a[i]<min) min = a[i]; printf("%d ",a[i]); printf("\nminimo parcial %d proceso 3 ID %d \n", min,getpid()); fprintf(fp, "%d\n",min); fclose ( fp ); exit(0); case 4: printf("\n"); min = a[75]; imin = 0; for (i=75; i<=99; i++) if (a[i]<min) min = a[i]; printf("%d ",a[i]); printf("\nminimo parcial %d proceso 4 ID %d \n", min,getpid()); fprintf(fp, "%d\n",min); fclose ( fp ); exit(0); default: printf("no hay tal comando \n"); exit(0); exit(0);

Pipe En cuanto al mecanismo de comunicación de tuberías hablaremos poco ya que solo el sistema operativo lo utiliza para comunicación y que nos es más que la comunicación utilizando un archivo como se planteo en la sección anterior, y son pocos utilizados programadores, cabe comentar que a veces los comandos no se ejecutan en el orden en que se proporcionan. Ejemplo: Tenemos un archivo llamado pba.txt Y se le da al sistema operativo la orden siguiente #cat pba.txt sort n Conducto sin cat pba.txt sort -n nombre Proceso 1 Archivo temporal Proceso 2

El resultado es el siguiente: Existen dos tipo de tuberías una llamada tuberías sin nombres y una con nombre y pueden ser direccionales o bidireccionales

Memoria compartida La forma más rápida y una de las más usadas de comunicar dos procesos es hacer que compartan una zona de memoria. Para enviar datos de un proceso a otro, solo hay que escribir en memoria y automáticamente estos datos estarán disponibles para que los lea otro proceso.. M e m o r i a Var Llave acceso 44468 Apuntador Var Var Apuntador Proceso 1 Proceso 2 Recordemos que los procesos no comparten memoria, no basta con declarar la variable como global, si se quiere compartir memoria tiene que implementarse primero, además se tiene que usar semáforos como mecanismo de sincronización para proteger la sección critica.

Los paso son los siguiente Proceso Obtener un manejador A través de shmid= shmid(llave,sizeof(..), ); Anclar el segmento a una estructura definida dentro del proceso var=shmat(shmid,0,0); Leer /escribir var Quitar el ancla shmdt(var) Borrar segmento de memoria shmctl(shmid,ipc_rmid,0); Fin del Proceso Como ejemplo resolveremos el mismo problema visto al inicio de la comunicación entre procesos. #include <stdlib.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #include <stdio.h>

#include <errno.h> void spin_lock_init(); //inicializa los semáforos void spin_lock(); //P void spin_unlock();//v key_t shm_key; int shmid, semid, pid; char *shm; int *A, *addr; int i,j=10, *vol,*vol2;; int minimos[5]; int j,i,pid,status,proc; int cont,min,imin, a[100]; int process_fork(int nproc) int i; for(i=1;i<=nproc-1;i++) if(fork()==0) return(i); return(0); main() spin_lock_init(&semid); shm_key=0x5675; //shmget devuelve devuelve un entero shmid=shmget(shm_key,sizeof(minimos),(ipc_creat 0600)); vol=shmat(shmid,0,0); //shmat devuelve un puntero char vol2=vol; printf("valores del vector a[100]\n"); for(i=0;i<100;i++) a[i]=rand()%100; printf("%d ",a[i]); if(((cont+1)%25)==0)printf("\n");

cont++; printf("\n\n"); pid=process_fork(5); switch(pid) case 0: for(i=1;i<5;i++) wait(&i); printf("\n"); min=vol[0]; for(i=1;i<4;i++) if(vol[i]<min)min=vol[i]; printf("\n padre ID=%d valor minimo total %d\n",getpid(),min); exit(0); case 1: printf("\n"); min = a[0]; imin = 0; for (i=0; i<=24; i++) if (a[i]<min) min = a[i]; printf("%d ",a[i]); printf("\n padre ID=%d valor minimo total %d\n",getpid(),min); spin_lock(&semid); vol[pid-1]=min; spin_unlock(&semid); exit(0); case 2: printf("\n"); min = a[25]; imin = 0; for (i=25; i<=49; i++) if (a[i]<min) min = a[i]; printf("%d ",a[i]); printf("\n padre ID=%d valor minimo total %d\n",getpid(),min); spin_lock(&semid); vol[pid-1]=min; spin_unlock(&semid); exit(0); case 3:

printf("\n"); min = a[50]; imin = 0; for (i=50; i<=74; i++) if (a[i]<min) min = a[i]; printf("%d ",a[i]); printf("\n padre ID=%d valor minimo total %d\n",getpid(),min); spin_lock(&semid); vol[pid-1]=min; spin_unlock(&semid); exit(0); case 4: printf("\n"); min = a[75]; imin = 0; for (i=75; i<=99; i++) if (a[i]<min) min = a[i]; printf("%d ",a[i]); printf("\n padre ID=%d valor minimo total %d\n",getpid(),min); spin_lock(&semid); vol[pid-1]=min;; spin_unlock(&semid); exit(0); default: printf("no hay tal comando \n"); exit(0); if(semctl(semid,0,ipc_rmid,1)==-1) perror("semctl"); exit(1); if(shmctl(shmid,ipc_rmid,0)==-1) perror("shmctl"); exit(1); exit(0);

//inicializa los semaforos void spin_lock_init(int *lok) int init_sem_value=1; *lok=semget(ipc_private,1,(0600 IPC_CREAT)); if(*lok==-1) perror("semget"); exit(1); if(semctl(*lok,0,setval,init_sem_value)<0) perror("semctl"); exit(1); /*end of spin_lock_init */ // Operación P void spin_lock(int *lok) struct sembuf sembuffer, *sops; sops=&sembuffer; sops->sem_num=0; sops->sem_op=-1; sops->sem_flg=0; if(semop(*lok,sops,1)<0) perror("semop"); exit(1); /*end of spin_lock */ //operación V void spin_unlock(int *lok) struct sembuf sembuffer, *sops; sops=&sembuffer; sops->sem_num=0; sops->sem_op=1; sops->sem_flg=0; if(semop(*lok,sops,1)<0) error("semop"); exit(1);

/*end of spin_unlock */

in out Colas de mensajes El mecanismo conocido como cola de mensajes es una lista enlazada y almacenada en el núcleo la cual tienen un id, este último es similar al de memoria compartida y semáforos. De forma básica diremos que los mensajes tienen una estructura de acuerdo a los datos a ser almacenados, y opera de la siguiente manera mensaje n Etiqueta n.. mensaje 3 Etiqueta 3 mensaje 2 Etiqueta 2 mensaje 1 Etiqueta 1 Como podemos observar opera como una estructura de datos conocida como cola, a excepción de que si conoce la etiqueta (número) puede sacar el mensaje correspondiente sin necesidad de sacar los mensajes anteriores a el, a través de la función msgrcv( ). Cada mensaje consiste en dos partes, las cuales están definidas en la estructura struct msgbuf, tal como aparece en sys/msg.h: Donde: struct msgbuf long mtype; char mtext[1]; mtype Es usado para recibir mensajes, y puede ser cualquier número positivo. mtext Es el dato que se añadirá a la cola, este campo puede variar según las necesidades del programador. Esta estructura es la más básica, pero puede ampliarse a mas campos de datos, el único campo que es necesario es long mtype,

Además type msgrcv( ) 0 Recibe el próximo mensaje de la cola (el de arriba). > Se devuelve el primer mensaje cuyo msg_type sea igual a type. < se devuelve el primer mensaje cuyo msg_type sea el menor valor o igual que el valor absoluto de type Previamente describimos comandos para trabajar y verificar el estado de los mecanismos de comunicación, en este apartado solo hablaremos específicamente sobre el uso para colas de mensajes. Si queremos ver la colas activa del núcleo y su estado, tecleamos el #ipcs q Para eliminar una cola desde la línea de comandos tecleamos #ipcrm q id_cola

El siguiente ejemplo genera una colas de mensaje, envía datos y los saca como una pila, esto se logra dando valores mayores que cero a type en la función msgrcv. //cola1.c #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define BUFSZ 512 /* estructura del mensaje*/ struct msg long msg_type; char msg_text[bufsz]; pmsg; /*puntero a la estructura de mensaje*/ main(int argc, char *argv[]) int qid; /*identificador de la cola */ key_t key; /*clave de la cola */ int cont=0,len; /*el tamaã±o de los datos enviados*/ int cont2; long etiq; //creando la llave de la cola de mensaje key=ftok("hola",'h'); //crea la cola */ if((qid=msgget(key, IPC_CREAT 0666))<0) perror("msgget:create"); exit(exit_failure); printf("creado ID de cola = %d \n ",qid); printf("para terminar el envio de mensajes enter\n"); for(;;) printf("mensaje a enviar: -> "); fgets((&pmsg)->msg_text, BUFSZ, stdin); len=strlen(pmsg.msg_text); if(len==1) puts("fin de envio"); break; cont++; /*asocia el mensaje con este proceso*/ pmsg.msg_type=cont; msgsnd(qid, &pmsg,len,0); printf("etiqueta -> %d mensaje -> %s enviado \n",cont,pmsg.msg_text); cont2=cont; for(;;)

if(cont2==0) msgctl(qid,ipc_rmid,null); printf("\n cola %d eliminada \n ",qid); exit(exit_success); msgrcv(qid, &pmsg,bufsz,cont2,0); printf("mensaje -> %s ",(&pmsg)->msg_text); cont2--;

Otra modificación que se puede realizar es poner todas las etiquetas (type) con números negativos y se volverá a comportar como una pila. La cola creada y conociendo su ID se pueden conectar varios proceso sin tener ancestros en común, o también generar varias colas y conectarse a ellas, el ejemplo siguiente crea dos colas de mensajes y simula como dos cajas de un súper mercados, al final del día saca el total de la venta del día. //colas.c #include <stdio.h> #include <stdlib.h> #include <sys/msg.h> #include <string.h> #include <time.h> int nfork (int np) int i; for (i=1;i<=np;i++) if (fork()==0) return(i); return(0); struct men long menid; char nom[10]; int dato; pmen; main (void) int cid1,cid2,pid=0,i,total1=0,total2=0,total=0; int cont=1; key_t key1,key2; key1=1020; key2=2400; cid1=msgget(key1,ipc_creat 0666); cid2=msgget(key2,ipc_creat 0666); pid=nfork (2); switch (pid) case 0: //printf ("Padre \n"); for(i=0;i<2;i++)wait(&i); printf("productos caja uno \n"); for (i=0;i<5;i++) msgrcv (cid1, &pmen, sizeof(pmen), 0,0); printf("%s %d \n",pmen.nom,pmen.dato);

total1+=pmen.dato; printf ("Total caja uno : %d \n",total1); msgctl (cid1,ipc_rmid,null); printf("\n"); printf("productos caja dos \n"); for (i=0;i<3;i++) msgrcv (cid2, &pmen, sizeof(pmen), 0,0); printf("%s %d \n",pmen.nom,pmen.dato); total2+=pmen.dato; printf ("Total caja dos : %d \n",total2); msgctl (cid2,ipc_rmid,null); printf ("\nventa del dia= %d \n",total1+total2); exit (0); case 1: //printf ("Hijo 1 \n"); srand(getpid()); printf ("producto registrado en caja 1 \n"); for (i=0;i<5;i++) total=(1+rand()%50); printf ("producto registrado en caja 1 \n"); pmen.menid=total; pmen.dato=total; sprintf(pmen.nom,"producto-%d",cont); msgsnd (cid1,&pmen,sizeof(pmen), 0); cont++; exit (0); case 2: //printf ("Hijo 2 \n"); srand(getpid()); for (i=0;i<3;i++) total=(1+rand()%50); printf ("producto registrado en caja 2\n"); pmen.menid=total; pmen.dato=total; sprintf(pmen.nom,"producto-%d",cont); msgsnd (cid2,&pmen,sizeof(pmen), 0); cont++; exit (0); default: printf ("Error al crear procesos \n"); exit (0);

Sockets Es un mecanismo que comunica dos proceso, que pueden intercambiar diferente tipos de datos ya sea que los procesos estén corriendo en un computadora o en un red de computadoras, además guarda cierta similitud con las tuberías (pipe). Para que la comunicación se establezca entre los procesos es necesario los siguientes aspectos: Una dirección IP, un protocolo y un número de puerto. Para conseguir esto aparece el concepto de conector o socket: dos procesos distintos crean cada uno su conector por lo tanto. 1. Cada conector esta ligado a una dirección. 2. Un proceso puede enviar información, a través de un socket propio, al socket de otro proceso, siempre y cuando conozca la dirección asociada (la del otro socket). La comunicación se realiza entre una pareja de sockets. Dominios y direcciones Definimos un dominio de comunicación como una familia de protocolos que se pueden emplear para conseguir el intercambio de datos entre sockets. Un sistema UNIX particular puede ofertar varios dominios, aunque los más habituales son estos dos: 1. Dominio UNIX (PF 1 _UNIX) Para comunicarse entre procesos dentro de la misma máquina. 2. Dominio Internet(PF_INET). Para comunicarse entre procesos en dos computadoras conectadas mediante los protocolos de Internet (TCP-UDP/IP). Además un sockets del dominio PF_UNIX no puede dialogar con sockets del dominio PF_INET. Cada familia de protocolos define una serie de convenciones a la hora de especificar los formatos de las direcciones. Tenemos, por lo tanto, estas dos familias de direcciones: 1. Formato UNIX(AF 2 _UNIX). Una dirección de socket es como nombre de fichero(pathnmae). 1 PF significa Protocol Family 2 AF significa una Address Family

2. Formato Internet(AF_INET). Una dirección de sockets precisa de estos tres campos: a) Una dirección de red de la maquina (Dirección IP). b) Un protocolo (TCP o UDP) y c) Un puerto correspondiente a ese protocolo. Es importante resaltar que un socket puede ser referenciado desde el exterior solo si su dirección es conocida. Sin embargo, se puede utilizar un socket local aunque no se conozca la dirección que tiene. Estilos de comunicación Orientados a conexión:- Mecanismo que sirven para conseguir un canal para el intercambio de octenos. Un proceso pone, a su ritmo, bytes en el canal, que recibe de forma fiable y ordenada en el otro extremo, donde hay un proceso que los recoge a su conveniencia. Ejemplo: pipes y los socketpairs Comunicación sin conexión:- también denominada comunicación con datagramas. El emisor envía mensajes envía un mensaje autónomo que el receptor debe recibir enteros. Por el camino algún mensajes pueden perderse, retrasarse o llegar desordenados. La comunicación entre dos sockets puede realizarse con cualquiera de estas dos formas (aunque los dos sockets comunicantes deben de hacerse creados con el mismo estilo, ademas de el mismo dominio). Para ello, al crear un socket se indica el estilo de comunicación correspondiente: SOCK_STREAM la comunicación pasa por tres fases 1. Apertura de conexión 2. Intercambio de datos 3. Cierre de conexión El intercambio de datos es fiable y orientado a octenos (como los pipes): no hay frontera de mensajes SOCK_DGRAM. No hay conexiones. Cada mensaje (o datagrama) es autocontenido. Los datagramas no se mezclas se mezclan unos con otros. No hay garantia de entrega: se pueden perder, estropear o desordenar.

Protocolos Un protocolo es un conjunto de reglas, formato de datos y convenciones que es necesario respetar para conseguir la comunicacion entre dos entidades, ejemplos: IP, TCP, UDP, FTP, ETC., Cuando se crea un socket es necesario indicar cual es el protocolo de trasporte a emplear para el intercambio de datos que se realizara a traves de el. La mayoría de las aplicaciones con socket de tipo INTERNET trabjan bajo el paradigma cliente servidor el proceso se da de la forma siguiente: Operaciones del servidor operaciones cliente Crea un socket Anclar a un puerto Escuchar a través del puerto y definir cola de peticiones Crea un socket Aceptar la conexión Conectarse al puerto del servidor Leer/Escribir en la conexión Leer/Escribir en la conexión Cerrar la conexión Cerrar la conexión

Llamadas de sistemas para la creación y uso de sockets Creación de socket Un proceso puede crear un socket utilizando la función socket(). Su prototipo es este: #include <sys/types.h> #include <sys/socket.h> int socket(int domain, int type, int protocol); protocolo sirve para especificar el protocolo de comunicación a emplear, en general este argumento es 0, indicando que se usa el protocolo por omisión. Asociar el socket a un puerto: bind() Una vez creado el socket necesitamos anclarlo a un puerto para que el proceso tenga que escuchar atreves de ese puerto. Y se hace utilizando la llamada del sistema bind(). int bind(int nomsocket, const struct sockaddr *dirsocket, size_t dirsocket_longitud) Donde: nomsocket dirsocket dirsocket_longitud Socket creado a partir de la llamada bind() Contiene todos los datos asociados a una dirección donde se va a trasmitir a través del socket Contiene el tamaño de la direccion bind() regresa 0 si tuvo éxito, en caso contrario -1 que indica que existe un error Escuchando en el puerto: listen() Una vez creado, anclado a un puerto, es momento de ponerse a escuchar y s utiliza llamada del sistemas listen(). Int listen(int nomsocket, int num_max_proc)

Donde: nomsocket Num_ma_proc Socket creado a partir de la llamada bind() Número máximo de procesos en espera listen() regresa 0 si tuvo éxito, en caso contrario -1 que indica que existe un error Aceptando una llamada: accept() En protocolos orientados a comunicación el servidor debe esperar una petición de conexión para crear un canal de comunicación a través del cual se dará el envió y recepción de datos entre procesos. Se utiliza la llamada del sistema accept(). int accept(int nomsocket, struct sockaddr *ctladdr, int *addrlen) Donde: nomsocket ctladdr addrlen Descriptor del socket Dirección del proceso con el que se estableció el canal de comunicación (cliente) Longitud de la dirección accept() regresa 0 si tuvo éxito, en caso contrario -1 que indica que existe un error. Conectándose al puerto: connect() Esta llamada de sistema es usada por el cliente para solicitar una conexión al servidor. int connect(int nomsocket, struct sockaddr *servaddr, int *addrlen) Donde: nomsocket ctladdr addrlen Descriptor del socket Dirección del servidor Longitud de la dirección connect() regresa 0 si tuvo éxito, en caso contrario -1 que indica que existe un error. Recepción de mensajes: read(), recv() y recvfrom() Enviando mensajes: write(), send() y sendto() Cerrando la comunicación: close()

Comunicación con socketpairs Este mecanismo es muy similar a las tuberías solo que con la particularidad de que son bidireccionales y solos son usados cuando los procesos tienen un ancestro en común. Para creas un socketpairs se hace de la siguiente función: #include <sys/types.h> #include <sys/socket.h> Int socketpair(int domain, int type, int protocolo, int vecsock[2]

Las tareas que se deben realizar se muestran en la siguiente tabla PADRE HIJO Crear un socketpair Crear el hijo Leer un mensaje Escribir un mensaje Terminar Escribir un mensaje Leer un mensaje Terminar Ejemplo: //sockepair.c #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define men1 "papa esta ahi" #define men2 "aqui estoy hijo" main() int n,sockets[2], child; char buf[1024]; if(socketpair(pf_unix,sock_stream,0,sockets)<0) perror("abriendo el par de sockets\n"); exit(1); if ((child=fork())==-1) perror("creando el proceso hijo\n"); else if(child) //este es el padre close(sockets[0]); if(read(sockets[1],buf,1024)<0) perror("padre leyendo el mensaje \n"); printf("id padre = %d mensaje de mi hijo --> %s \n",getpid(),buf); if(write(sockets[1],men2,strlen(men2)+1)<0) perror("padre escribiendo el mensaje"); printf("id padre = %d respuesta --> %s \n",getpid(),men2); close(sockets[1]); exit(1); else /*este es el hijo */ close(sockets[1]);

printf("id hijo = %d pregunta --> %s\n",getpid(),men1); if(write(sockets[0],men1,strlen(men1)+1)<0) perror("hijo escribiendo mensaje"); wait(&n); if(read(sockets[0],buf,1024)<0) perror("hijo leyedo mensaje\n"); printf("id hijo = %d respuesa de papa--> %s\n",getpid(),buf); close(sockets[0]); Datagrama en el dominio UNIX Para ejemplificar utilizaremos dos programas uno que actuara como emisor y otro como receptor, la tarea del emisor es enviar un mensaje al receptor y el receptor la recibe y muestra el mensaje. //receptor sock-dgram-receptor.c //Ejemplo sobre data gramas en el dominio PF_UNIX //extremo receptor //proceso para el intercambio de información //1.- ejecutamos el receptor //2.- Ejecutar el emisor #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define NAME "socketunix" main() int sock, length, lon2; struct sockaddr_un name; char buf[1024]; sock=socket(pf_unix, SOCK_DGRAM,0);

if(sock<0) perror("abriendo socket de dtagramas"); exit(1); name.sun_family=af_unix; strcpy(name.sun_path,name); if(bind(sock,(struct sockaddr *)&name,sizeof(name))<0) perror("asociado con nombre al socket"); exit(1); printf("direccion del socket -> %s \n",name); if(recvfrom(sock,buf,1024,0,null,&lon2)<0) perror("recibiendo un datagrama"); printf("id proceso %d --> %s\n",getpid(),buf); close(sock); unlink(name); exit(0); // Emisor sock-dgram-emisor.c //ejemplo sobre datagrama en el dominio PF_UNIX //Extremo Emisor #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define DATA "emisor esta ahiiiiiiiiiii" main(int argc, char *argv []) int sock; struct sockaddr_un name; sock=socket(pf_unix, SOCK_DGRAM,0); if(sock<0) perror("abriendo scoket de datagrama"); exit(1); name.sun_family=af_unix; strcpy(name.sun_path,argv[1]); printf("id proceso %d pregunta: --> %s\n",getpid(),data); if(sendto(sock,data,strlen(data)+1,0,(struct sockaddr *)&name,sizeof name)<0) perror("enviando un datagrama"); close(sock); exit(0);\

Socket tipo INTERNET en modo comunicación Conexión simultaneas Consiste en crear aplicaciones concurrentes bajo el esquema cliente-servidor, en este caso creamos un servidor multiprocesos, el proceso principal crea procesos hijos los cuales se les asigna una la tarea de atender la petición de algún servidor os sea cada servidor le corresponde un proceso hijoi(i) /*Serveco3.c : Un servidor de eco orientado a conexión concurrente*/ /* multiproceso basado en sockets.*/ #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include<signal.h> #include <errno.h> /*----------------------------------------------------------------------------*/ void do_echo(int); /*----------------------------------------------------------------------------*/ extern int errno; /*----------------------------------------------------------------------------*/ void do_echo(int fd) char buf[4096],resp[100]; int cc,org,faltan,cc2,opc; //read(int fd, void *buf, size_t nbyte); //fd descriptor del socket(ssocket) //buf almacena la lectura //sizeof(buf) tamaño de buf while (cc=read(fd,buf,sizeof(buf))) if (cc<0) perror("read"); exit(6); //printf("buf %s opc=%d \n",buf,opc); //printf("lect-> %s longitud %d \t",buf,strlen(buf)); switch(buf[0]) case '0':strcpy(resp,"number zero\n"); break; case '1':strcpy(resp,"number one\n"); break; case '2':strcpy(resp,"number two\n"); break; default: strcpy(resp,"fuera de rango[0,2]\n"); break; org=0;

faltan=strlen(resp); /*Los que hay que mandar*/ //write(int fd, void *buf, size_t nbyte); while (faltan) /// if ((cc2=write(fd,&resp[org],faltan))<0) perror("fallo al escribir"); exit(7); org+=cc2; faltan-=cc2; close(fd); /*----------------------------------------------------------------------------*/ int main() struct sockaddr_in sin,fsin; int s,ssock,alen;//read(int fd, void *buf, size_t nbyte); sin.sin_family=af_inet; sin.sin_addr.s_addr =htonl(inaddr_any); sin.sin_port =htons(4000); //crea socket //s=/-1 entonces error if ((s=socket(pf_inet,sock_stream,0))<0) perror("no se puede crear el socket"); exit(1); //asocia el socket a un puerto los datos se dant //en los campos de la estructura sin if (bind (s,(struct sockaddr *)&sin,sizeof(sin))<0) perror("no se puede asignar la dirección"); exit(2); //escucha s id-sock, 5 el numnero max de proceso en espera if (listen(s,5)<0) perror("no puedo poner el socket en modo escucha"); exit(3); signal(sigchld, SIG_IGN); while (1) alen=sizeof(fsin); //acepta o se emite mensajes //*fsin direccion en donde el proceso establecio el canal de comunicacion el cliente //*alen longitud de la direccion if ((ssock =accept(s, (struct sockaddr *)&fsin,&alen))<0) if (errno == EINTR) continue; perror("fallo en funcion accept"); exit(4); switch (fork())

case -1: perror("no puedo crear hijo"); exit(5); case 0 : close(s); /*Proceso hijo*/ do_echo(ssock); break; default: close(ssock); break;

Bibliografia TCP/IP en Unix programación de aplicaciones distribuidas Jose Miguel Alonso RA-MA