i have two son processes that read from a file and send the results to the father process, but when the childs have sent the strings the father receives the strings plus some other strange chars … how do i null terminate the string received and how do i make the father wait for all the sons that might have more work to do after sending some of the results…because the sons might send other results later …
Thanks for the help …
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdio.h>
#include <strings.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#define max_chars_string 1000
#define n_childs 2
pid_t childs[n_childs];
int channel[n_childs][2];
void read_lines(char * filename, char (*pointer)[max_chars_string],int init_read,int n_lines);
void get_strings_hash(char (*pointer_strings)[max_chars_string],char (*pointer_hashes)[max_chars_string],int total_lines);
void worker(int mypipe,char filename[],int n_lines){ // meter as funcoes de ler passwords no filho
int resources[2];// numero de linhas que cada processo tem de ler
int i = 0;
//definicao arrays
char strings_hashes[n_lines][max_chars_string];//aray de string com as strings lidas do ficheiro
char * pointer_strings = &strings_hashes[0][0];//ponteiro para o inicio do array das hashes
read_lines(filename,strings_hashes,0,n_lines); // le as strings do ficheiro e passa para o array
for(i = 0;i<n_lines;i++){
printf("%s \n",strings_hashes[i]);
}
printf("[%d] My parent is: %d\n", getpid(), getppid());
//open pipe to write and close pipe to read
close(channel[mypipe][0]);
i = 0;
int incr = 0;
while (i<n_lines) {
printf("[Son] Password sent e %s: \n",strings_hashes[incr]);
write(channel[mypipe][1], strings_hashes[incr], strlen(strings_hashes[incr]));
incr++;
i++;
}
exit(0);
}
int main(int argc, char **argv)
{
char *filename;
int status;//status do processos filho
int resources[2];// numero de linhas que cada processo tem de ler
int n_lines; //numero de linhas do ficheiro
int i = 0;
// Create a pipe
filename = (char*)malloc(strlen(argv[1])*sizeof(char)+1);
if(argc !=3){
fprintf(stderr, "Usage : %s [text_file] [cores]",argv[0]);
exit(0);
}
strcpy(filename,argv[1]);
char get_file [strlen(filename)];
strcpy(get_file,filename);
// start the processes
for(i = 0; i <atoi(argv[2]);i++){
pipe(channel[i]);
childs[i] = fork();
if(childs[i] == -1){
perror("Failed to fork");
return 1;
}
if (childs[i] == 0)
{
worker(i,get_file,n_lines);
}
close(channel[i][1]);
}
i = 0;
int k = 0;
int fd;
fd_set read_set;
FD_ZERO(&read_set);
char string_lida [30];
// working father
printf("[%d] I'm the father!\n", getpid());
printf("[Father]orking ...\n");
//unammed_pipes connection
while(k<n_childs){
FD_SET(channel[0][0], &read_set);
for(i=0;i<n_childs;i++){
FD_SET(channel[i][0], &read_set);
if(fd<channel[i][0]){ fd=channel[i][0];
}
}
if(select(fd+1,&read_set,NULL,NULL,NULL)>0){
for(i=0;i<n_childs;i++){
if(FD_ISSET(channel[i][0], &read_set)){
read(channel[i][0],string_lida,sizeof(string_lida));
printf("[Father]pipe %d - string lida:%s\n",i,string_lida);
k++;
}
}
}
fd=1;
}
//
//waiting for childs ...
for(i=0;i<n_childs;i++){
wait(&status);
printf("waiting for childs \n");
}
return 0;
}
void get_strings_hash(char (*pointer_strings)[max_chars_string],char (*pointer_hashes)[max_chars_string],int total_lines)//vai ao array de strings e corta a parte de hash e mete num array
{
int i = 0;
char *strings;
char *hash;
for(i = 0;i<total_lines;i++){
strings = (char*)malloc(strlen(pointer_strings)*sizeof(char)+1);
strcpy(strings,*pointer_strings);
hash = (char*)malloc(strlen(pointer_strings)*sizeof(char)+1);
find_hash(strings,hash);
strcpy(*pointer_hashes,hash);
pointer_hashes++;
pointer_strings++;
}
}
void read_lines(char * filename, char (*pointer)[max_chars_string],int init_read,int n_lines){
FILE *fp;
char str[max_chars_string];
int i =0;
if((fp = fopen(filename, "r"))==NULL) {
printf("Cannot open file.\n");
exit(1);
}
if(init_read>0 && init_read<=n_lines){
for(i = 0;i<init_read;i++){
fgets(str, sizeof str, fp);
for(i = init_read;i<n_lines;i++){
fgets(str, sizeof str, fp);
strcpy(*pointer, str); //copia para a posicao actula do ponteiro
pointer++;
}
}
}
if(init_read<=n_lines && init_read==0){
for(i = init_read;i<n_lines;i++){
fgets(str, sizeof str, fp);
strcpy(*pointer, str); //copia para a posicao actula do ponteiro
pointer++;
}
}
fclose(fp);
}
When the child does
strlen() doesn’t count the null terminator of the string. So when the parent reads from the pipe, it doesn’t receive a null-terminated string. Then when it does:
It keeps printing past the end of what was written, because there’s no string terminator.
Also, there’s no guarantee that the amount read by read() will match up with the amount written each time write() was called. If the child writes two strings before the parent reads from the pipe, it may get all or parts of both, or it could get even less than was written.
You need to implement a way to indicate where the string boundaries are. You could send the size of the string first as one or two bytes, or you could use a null terminator. When the parent is reading, it needs to do this in a loop until it gets a whole string, and if it goes past the end it may need to save it in a buffer.