elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Como proteger una cartera - billetera de Bitcoin


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  Programacion en C
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Programacion en C  (Leído 4,349 veces)
Andrea0000

Desconectado Desconectado

Mensajes: 5


Ver Perfil
Programacion en C
« en: 2 Enero 2022, 15:17 pm »

Buenas he hecho este codigo pero me queda por implementar una linea de codigo acerca de read que lea un caracter de entrada de la tuberia fd[0] y la verdad no se como hacerlo. Se encuentra en el for: /*Espera a la finalizacion de los procesos hijos*/

Código:
#define _POSIX_SOURCE
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <wait.h>

#define NUM_HIJOS 10//El numero de hijos debe ser tantos como numero de parametros haya
#define NOMBREHIJO "./hijo"

void FinalizarProcesos();

void Manejador(int num);

pid_t pids[NUM_HIJOS];
int longitud_pid=0;//logitud del pid

int main(int argc, char *argv[]){
int fd[2];//Descriptores de la tuberia de comunicacion
int i, j; //Para los bucles
int pid; //PID de un proceso hijo

int status; //terminacion proceso hijo

/*Tratamiento de la linea de ordenes*/
if(argc < 2){// < 2
fprintf(stderr, "Error en el numero de argumentos\n");
exit(EXIT_FAILURE);
}

/*Tratamiento de la señal*/
if(signal(SIGINT, Manejador)== SIG_ERR){
fprintf(stderr, "Error en la manipulacion de la señal\n");
exit(EXIT_FAILURE);
}

/*?? Creacion de la tubería de comunicacion*/
if(pipe(fd) != 0){
fprintf(stderr, "Error en la creacion de la tuberia\n");
return EXIT_FAILURE;
}

//CREACION DE LOS PROCESOS HIJOS
for(i=1; i<NUM_HIJOS; i++){
switch(pids[i-1]=fork()){ //Se guarda el pid en la tabla de procesos y con pids[i-1]se salta el ./padre
case -1:
fprintf(stderr, "Error en la creacion del proceso hijo\n");
return EXIT_FAILURE;
break;
case 0: //Ejecucuion por el proceso hijo
close(1);
if(dup(fd[1]) != 1){// Asignacion de salida estandar
fprintf(stderr, "Error en la duplicacion del descriptor\n");
return EXIT_FAILURE;
}
if(execl(NOMBREHIJO, NOMBREHIJO, argv[i], NULL) == -1){ //argv[1]
fprintf(stderr, "Error en la ejecucion del proceso hijo\n");
exit(EXIT_FAILURE);
}
break;
default: /*Ejecucion por el proceso padre*/
close(fd[1]);
break;
}
longitud_pid++; //Para tener un control de cuantas cosas hay dentro del pids, por ejemplo hola (longitud=1) mundo (longitud=2)
}

/*Espera a la finalizacion de los procesos hijos*/
for(i=1; i<NUM_HIJOS; i++){
pid=wait(NULL);
//leer un caracter de entrada de la tuberia fd[0] (READ)
}
printf("[Proceso padre] finaliza\n");
return EXIT_SUCCESS;
}

/*FinalizarProcesos: Termina todos los procesos hijos vivos*/
void FinalizarProcesos(void){
int i;
for(i=0; i<longitud_pid; i++){ //Logitud_pid es porque los pids leidos van a tener valor
if(kill(pids[i], SIGTERM) == -1){
fprintf(stderr, "Error al enviar una señal\n");
exit(EXIT_FAILURE);
}

}
}


/*Manejador: Manejador de señal*/
void Manejador(int num){
FinalizarProcesos();
printf("[Proceso padre] finaliza\n");
exit(EXIT_SUCCESS);
}


En línea

RayR

Desconectado Desconectado

Mensajes: 239


Ver Perfil
Re: Programacion en C
« Respuesta #1 en: 2 Enero 2022, 20:20 pm »

Pues se usa igual que con cualquier tipo de archivo:

Código
  1. read(fd[0], buffer, NUM_BYTES);

Al margen de eso, revisa bien tu código y apuntes que tengas, ya que tiene varios errores. Por mencionarte algunos:

Siempre es importante cerrar los descriptors no usados, así que los hijos deberían cerrar fd[0]. De igual forma, después del dup, ya no usas fd[1] directamente (execl usa el descriptor de stdout, que apunta hacia tu pipe), por lo que también es mejor cerrarlo. Por cierto, dup2 es más recomendable que dup, aunque esto es sólo un consejo.

Estás cerrando fd[1] desde dentro del bucle, lo que significa que, a partir de la segunda iteración, estarás intentado duplicar un descriptor ya cerrado. Ese close debe ir fuera del for.

No estás terminando los procesos hijos, así que algunos de ellos van a crear sus propios procesos hijos, además de ejecutar lo que está fuera del bucle, adonde, se supone, sólo debería llegar el padre. Así que debes agregar un exit al final del case 0. Ya que estamos, normalmente es preferible que los procesos hijos finalicen con _exit en vez de exit. En tu caso no lo cambies, pero tenlo en cuenta. Si en algún ejercicio posterior tienes problemas (por ejemplo, que los mensajes salgan repetidos), busca las diferencias entre ambas funciones, ya que ahí podría estar la solución.


En línea

Andrea0000

Desconectado Desconectado

Mensajes: 5


Ver Perfil
Re: Programacion en C
« Respuesta #2 en: 3 Enero 2022, 10:20 am »

Gracias por tu ayuda @RayR. He intentado hacer los cambios según he entendido, pero a la hora de compilarlo no me da un error pero cuando ejecuto el proceso padre con (./padre.o hola mundo) me aparece errores como:
-Error en la ejecucion del proceso hijo
-[Proceso padre] finaliza
Adjunto el código con los cambios.

Código:

#define _POSIX_SOURCE
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <wait.h>

#define NUM_HIJOS 10//El numero de hijos debe ser tantos como numero de parametros haya
#define NOMBREHIJO "./hijo"

void FinalizarProcesos();

void Manejador(int num);

pid_t pids[NUM_HIJOS];
int longitud_pid=0;//logitud del pid

int main(int argc, char *argv[]){
int fd[2];//Descriptores de la tuberia de comunicacion
int i, j; //Para los bucles
int pid; //PID de un proceso hijo

int status; //terminacion proceso hijo

/*Tratamiento de la linea de ordenes*/
if(argc < 2){// < 2
fprintf(stderr, "Error en el numero de argumentos\n");
exit(EXIT_FAILURE);
}

/*Tratamiento de la señal*/
if(signal(SIGINT, Manejador)== SIG_ERR){
fprintf(stderr, "Error en la manipulacion de la señal\n");
exit(EXIT_FAILURE);
}

/*?? Creacion de la tubería de comunicacion*/
if(pipe(fd) != 0){
fprintf(stderr, "Error en la creacion de la tuberia\n");
return EXIT_FAILURE;
}

//CREACION DE LOS PROCESOS HIJOS
for(i=1; i<NUM_HIJOS; i++){
switch(pids[i-1]=fork()){ //Se guarda el pid en la tabla de procesos y con pids[i-1]se salta el ./padre
case -1:
fprintf(stderr, "Error en la creacion del proceso hijo\n");
FinalizarProcesos();
break;
case 0: //Ejecucuion por el proceso hijo
close(1);
if(dup(fd[1]) != 1){// Asignacion de salida estandar
fprintf(stderr, "Error en la duplicacion del descriptor\n");
return EXIT_FAILURE;
}
if(execl(NOMBREHIJO, NOMBREHIJO, argv[i], NULL) == -1){ //argv[1]
fprintf(stderr, "Error en la ejecucion del proceso hijo\n");
return EXIT_FAILURE;
}
return EXIT_FAILURE;
break;
default: /*Ejecucion por el proceso padre*/

break;
}
longitud_pid++; //Para tener un control de cuantas cosas hay dentro del pids, por ejemplo hola (longitud=1) mundo (longitud=2)
}
close(fd[1]);


/*Espera a la finalizacion de los procesos hijos*/
for(i=1; i<NUM_HIJOS; i++){
pid=wait(NULL);
read(fd[0], pids, sizeof(pids));
//leer un caracter de entrada de la tuberia fd[0] (READ)
}
printf("[Proceso padre] finaliza\n");
return EXIT_SUCCESS;
}

/*FinalizarProcesos: Termina todos los procesos hijos vivos*/
void FinalizarProcesos(void){
int i;
for(i=0; i<longitud_pid; i++){ //Logitud_pid es porque los pids leidos van a tener valor
if(kill(pids[i], SIGTERM) == -1){
fprintf(stderr, "Error al enviar una señal\n");
exit(EXIT_FAILURE);
}

}
}


/*Manejador: Manejador de señal*/
void Manejador(int num){
FinalizarProcesos();
printf("[Proceso padre] finaliza\n");
exit(EXIT_SUCCESS);
}
En línea

RayR

Desconectado Desconectado

Mensajes: 239


Ver Perfil
Re: Programacion en C
« Respuesta #3 en: 3 Enero 2022, 16:26 pm »

Ese mensaje en tu programa indica que falló execl. Asegúrate de que el archivo "hijo" exista en el mismo directorio que "padre", y que sea ejecutable. Puedes ver más detalles sobre el error si después del fprintf que muestra "Error en la ejecucion del proceso hijo\n", pones:

Código
  1. perror("execl");

Y te digo otra vez, revisa bien el código y lee los apuntes o manuales que tengas, porque todavía hay más errores. Por ejemplo, tu read está mal, ya que el segundo parámetro debería ser una cadena de caracteres. Y a execl le estás pasando argv[ i ]: tal y como tienes el for, eso es incorrecto. Revísalo bien y verás por qué.

Los procesos hijos deberían terminar con _exit o exit, no con return; no sé por qué cambiaste eso. De cualquier forma forma, esa última línea del case 0 no debería retornar EXIT_FAILURE; eso es sólo cuando se finaliza con error. Y ahora que lo vuelvo a ver, estrictamente hablando, en tu programa no necesitarías ese último exit (o return), ya que los hijos están llamando a execl (que los reemplaza por procesos nuevos), pero de todas formas es importante acostumbrarte a finalizar siempre todos tus procesos hijos.
En línea

Andrea0000

Desconectado Desconectado

Mensajes: 5


Ver Perfil
Re: Programacion en C
« Respuesta #4 en: 3 Enero 2022, 18:27 pm »

Ese mensaje en tu programa indica que falló execl. Asegúrate de que el archivo "hijo" exista en el mismo directorio que "padre", y que sea ejecutable. Puedes ver más detalles sobre el error si después del fprintf que muestra "Error en la ejecucion del proceso hijo\n", pones:
Si, tanto el proceso padre como el proceso hijo ambos estan en el mismo directorio, he puesto la linea de codigo que me has dicho y cuando ejecuto me devuelve:
Error en la ejecucion del proceso hijo
execl: No such file or directory
He intentado solucionarlo, pero segun he visto en los apuntes y en el manual no he conseguido ver los fallos, no se porque tiene fallos de directorio, si tanto el hijo como el padre estan en el mismo directorio


Por ejemplo, tu read está mal, ya que el segundo parámetro debería ser una cadena de caracteres. Y a execl le estás pasando argv[ i ]: tal y como tienes el for, eso es incorrecto. Revísalo bien y verás por qué.

-Ahi he creado un buffer de lectura/escritura, creo que con ello me basta aunque tenia dudas de que en vez de crear un buffer poner la variable NOMBREHIJO
-En cuanto al for no se a cual de los dos se refiere, pero he analizado ambos y no encuentro lo que dices que es incorrecto, no se si te refieres a esto:
 
Código:
if(execl(NOMBREHIJO, NOMBREHIJO, argv[1], NULL) == -1){ //argv[1]
fprintf(stderr, "Error en la ejecucion del proceso hijo\n");
    perror("execl");
exit(EXIT_FAILURE);
alli en vez de argv, he puesto argv[1], no se si ese seria el fallo que me dices...
[/b]

Los procesos hijos deberían terminar con _exit o exit, no con return; no sé por qué cambiaste eso. De cualquier forma forma, esa última línea del case 0 no debería retornar EXIT_FAILURE; eso es sólo cuando se finaliza con error. Y ahora que lo vuelvo a ver, estrictamente hablando, en tu programa no necesitarías ese último exit (o return), ya que los hijos están llamando a execl (que los reemplaza por procesos nuevos), pero de todas formas es importante acostumbrarte a finalizar siempre todos tus procesos hijos

Y esto es cierto :) acabo de fijarme en los manuales y es asi como dice. Gracias!

adjunto el codigo del proceso padre nuevamente y el del hijo a continuacion:


HIJO
Código:
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>

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

/*Tratamiento de la linea de ordenes*/
if(argc != 2){
fprintf(stderr, "Error en el numero de argumentos\n");
return EXIT_FAILURE;
}

//Para las señales
sleep(5); //El hijo se ejecuta se duerme 5 seg y va ha inprimir el 1º caracter por tubería
//Ve como se matan los procesos hijos.

putchar(argv[1][0]);  //El primer caracter en la salida estandar y escribe en la tuberia, imprime el primer caracter
return EXIT_SUCCESS;
}



PADRE
Código:
#define _POSIX_SOURCE
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <wait.h>

#define NUM_HIJOS 10//El numero de hijos debe ser tantos como numero de parametros haya
#define NOMBREHIJO "./hijo"
#define MAXBUFFER 256 //Tamaño del buffer lectura/escritura

void FinalizarProcesos();

void Manejador(int num);

pid_t pids[NUM_HIJOS];
int longitud_pid=0;//logitud del pid

int main(int argc, char *argv[]){
int fd[2];//Descriptores de la tuberia de comunicacion
int i, j; //Para los bucles
int pid; //PID de un proceso hijo

int status; //terminacion proceso hijo
char buffer[MAXBUFFER];//buffer de lectura/escritura
/*Tratamiento de la linea de ordenes*/
if(argc < 2){// < 2
fprintf(stderr, "Error en el numero de argumentos\n");
exit(EXIT_FAILURE);
}

/*Tratamiento de la señal*/
if(signal(SIGINT, Manejador)== SIG_ERR){
fprintf(stderr, "Error en la manipulacion de la señal\n");
exit(EXIT_FAILURE);
}

/*?? Creacion de la tubería de comunicacion*/
if(pipe(fd) != 0){
fprintf(stderr, "Error en la creacion de la tuberia\n");
return EXIT_FAILURE;
}

//CREACION DE LOS PROCESOS HIJOS
for(i=1; i<NUM_HIJOS; i++){
switch(pids[i-1]=fork()){ //Se guarda el pid en la tabla de procesos y con pids[i-1]se salta el ./padre
case -1:
fprintf(stderr, "Error en la creacion del proceso hijo\n");
FinalizarProcesos();
break;
case 0: //Ejecucuion por el proceso hijo
close(1);
if(dup(fd[1]) != 1){// Asignacion de salida estandar
fprintf(stderr, "Error en la duplicacion del descriptor\n");
return EXIT_FAILURE;
}
if(execl(NOMBREHIJO, NOMBREHIJO, argv[1], NULL) == -1){ //argv[1]
fprintf(stderr, "Error en la ejecucion del proceso hijo\n");
    perror("execl");
exit(EXIT_FAILURE);
}
break;
default: /*Ejecucion por el proceso padre*/
//close(fd[1]);// debe de ir fuera del for
break;
}
longitud_pid++; //Para tener un control de cuantas cosas hay dentro del pids, por ejemplo hola (longitud=1) mundo (longitud=2)
}
close(fd[1]);


/*Espera a la finalizacion de los procesos hijos*/
for(i=1; i<NUM_HIJOS; i++){
pid=wait(NULL);
read(fd[0], buffer, sizeof(buffer));//leerá la tuberia y la escribirá en la salida estandar
//leer un caracter de entrada de la tuberia fd[0] (READ)
}
printf("[Proceso padre] finaliza\n");
return EXIT_SUCCESS;
}

/*FinalizarProcesos: Termina todos los procesos hijos vivos*/
void FinalizarProcesos(void){
int i;
for(i=0; i<longitud_pid; i++){ //Logitud_pid es porque los pids leidos van a tener valor
if(kill(pids[i], SIGTERM) == -1){
fprintf(stderr, "Error al enviar una señal\n");
exit(EXIT_FAILURE);
}

}
}


/*Manejador: Manejador de señal*/
void Manejador(int num){
FinalizarProcesos();
printf("[Proceso padre] finaliza\n");
exit(EXIT_SUCCESS);
}
En línea

RayR

Desconectado Desconectado

Mensajes: 239


Ver Perfil
Re: Programacion en C
« Respuesta #5 en: 4 Enero 2022, 00:41 am »

Eso indica que no encuentra el archivo. ¿Seguro que se llama "hijo" y no "hijo.o" o algo así? Porque al parecer el ejecutable principal se llama "padre.o" (que realmente no debería tener esa extensión, pero eso es otro tema). De cualquier forma, puedes probar abriendo una terminal y desde el mismo directorio desde el que ejecutas padre, ejecuta el comando ./hijo, y ve si funciona.

En cuanto a argv, me refería a este for:

Código
  1. for(i=1; i<NUM_HIJOS; i++){

Como NUM_HIJOS vale 10, i tomará valores desde 1 a 9. Si al programa le pasas menos de 9 argumentos, llega un punto en el que con argv[ i ] estarás intentando ir más allá del final de argv. Nota también que el hecho de iniciar el for desde 1 significa que realmente estás limitando el número máximo de hijos a 9, no a 10, aunque creo que es un detalle sin mucha importancia.

Veo que luego vas a tener que imprimir lo que read lea. Algo que causa muchos problemas es olvidar que el búfer que te da esa función no necesariamente contiene caracter nulo '\0', así que es importante verificar el valor que te devuelve (el número de bytes leídos) y, o cierras manualmente la cadena, o le indicas a printf el número de caracteres a imprimir. Por ejemplo:

Código
  1. if ((num_caracteres = read(fd[0], buffer, MAXBUFFER)) > 0)
  2. printf("%.*s", num_caracteres, buffer);

Y te reitero, los hijos deberían cerrar fd[0], y, después del dup, fd[1]. Aunque en este caso no te dará problemas, es una mala práctica no hacerlo. Caso completamente distinto al del último exit de ese case 0, que, como te dije en el mensaje anterior, es redundante (aunque tampoco hace ningún mal). Al escribir mi primera respuesta, me enfoqué en los problemas con los pipes y fork y ni siquiera me fijé en que los hijos ejecutaban execl. Obviamente, al llamar a las funciones exec*, sólo es necesario finalizar la ejecución en caso de error, lo cual ya haces.
En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Mensajes similares
Asunto Iniciado por Respuestas Vistas Último mensaje
algunas dudas en programacion BATCH(nuevo en esto de programacion)
Scripting
stock_C 8 9,011 Último mensaje 19 Junio 2009, 18:08 pm
por frank30
programacion web vs programacion de escritorio
Programación General
lupitapro 2 7,569 Último mensaje 29 Mayo 2010, 05:51 am
por Dreamaker
Programacion Estructurada Vs Programacion Orientada a Objetos
Programación General
79137913 3 8,142 Último mensaje 1 Junio 2011, 18:02 pm
por 79137913
Programacion en C
Programación C/C++
Nachoppp 0 1,112 Último mensaje 2 Mayo 2018, 00:51 am
por Nachoppp
programacion
Programación C/C++
alex dom 1 1,196 Último mensaje 16 Noviembre 2018, 22:28 pm
por K-YreX
WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines