У меня проблема с 2 FIFO для чтения и записи в каждом

Прилагаемый код должен разрешать связь между двумя терминалами. Связь осуществляется через 2 FIFO, которые создаются в текущем каталоге. Программа должна открыть 2 fifo, и сын читает из STDIN и вставляет fifo1, а отец читает из другого fifo и печатает на терминале. Таким образом, связь происходит, так как вызов программы: ./myprog fifo1 fifo2 (для первого терминала) и ./myprog fifo2 fifo1 (для второго терминала). Код работает плохо, я подозреваю, что дочерняя функция write() работает в fifo не очень хорошо. Надеюсь, что я хорошо объяснил, помогите мне :'(

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <poll.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>

int main(int argc,char* argv[])
{
    if(argc<3)
    {
        printf("Error: Too few arguments...\n");
        exit(-1);
    }

    char** buffer_in=(char**) malloc(sizeof(char*));
    char** buffer_out=(char**) malloc(sizeof(char*));
    size_t dim_buff=sizeof(char*);
    FILE* stream;
    FILE* input;
    int fifo_in, fifo_out, num_poll_c, num_poll_f, read_count, i,write_b;
    pid_t pid;
    ssize_t length;
    struct pollfd* fd_set_c=(struct pollfd*) malloc(sizeof(int));//for the child
    struct pollfd* fd_set_f=(struct pollfd*) malloc(sizeof(int));//for the father


    printf("Write character e press enter:\n");

    if((fifo_in=open(argv[1],O_RDWR|O_NONBLOCK))==-1)
        perror("error open");
    if((fifo_out=open(argv[2],O_RDWR|O_NONBLOCK))==-1)
        perror("error open");

    if((input=fdopen(STDIN_FILENO,"r"))==NULL)
        perror("error fdopen");


    if((pid=fork())==-1)
        perror("error fork");
    while(1)
    {   
        if(pid==0)  /*child*/   
        {   
            fd_set_c->fd=STDIN_FILENO;
            fd_set_c->events=POLLIN;
            if((num_poll_c=poll(fd_set_c, 1, -1))==-1)
                perror("error poll child");//poll on fifo_in
            if((length=getline(buffer_in,&dim_buff,input))==-1)
                perror("error getline");



                printf("The written word is::%s\n",*buffer_in);/*my control for see what in buffer_in is*/


            if((write_b=write(fifo_in,*buffer_in,dim_buff))==-1)
                perror("error write");

        }

        else    /*father*/
        {   
            fd_set_f->fd=fifo_out;
            fd_set_c->events=POLLIN;

            if((num_poll_f=poll(fd_set_f, 1, 5000))==-1)
                perror("error poll father");//poll on fifo_out      
            if((read_count=read(fifo_out,*buffer_out,SSIZE_MAX))==-1)
                perror("error read");//read on fifo_out
            for(i=0;i<=read_count;i++)
                printf("%s",buffer_out[i]);//print on stdout buffer_out


        }
    }
    return 0;   

}

person Andrea    schedule 20.06.2010    source источник


Ответы (2)


Вы должны использовать каналы (man 2 pipe или общую память: man shmget) для связи между вашими процессами и семафор для защиты чтения/записи. Найдите в гугле «производитель/потребитель».

взгляните на это: http://users.evtek.fi/~tk/rtp/sem-producer-consumer.c и это: http://knol.google.com/k/producer-consumer-problem#

person Mat    schedule 20.06.2010
comment
Ммм... Меня немного озадачил ваш ответ: 1-это не обычный канал, а именованный канал (man 3 mkfifo) 2-данные защищены опросом(man 2 poll) 3-я не думаю, что я надо создать разделяемую память для FIFO! Или нет? - person Andrea; 20.06.2010

У вас тут бардак.

Родитель может заблокировать read() из FIFO, потому что для него все еще есть открытые для записи файловые дескрипторы. А дескриптор открытого для записи файла принадлежит самому родительскому процессу. И поскольку он заблокирован в read(), он не может писать в него.

Ставить открытие FIFO после fork(). Открыть в более строгом режиме: либо только на запись, либо только на чтение, а не wildcard O_RDWR. Таким образом, вы отразите логику, обычно применяемую к pipe().

Кроме того, poll() для STDIN_FILENO опасен, так как stdio буферизуется. Дескриптору файла может быть нечего читать - потому что он уже был прочитан ранее, но находится внутри буфера stdio. Если вы действительно уверены, что знаете, что делаете, попробуйте хотя бы отключить буферизацию, man setvbuf. Но я бы все равно не стал этого делать при наличии fork(): буферизованные данные могут быть прочитаны дважды: один раз дочерним и один раз родительским.

person Dummy00001    schedule 20.06.2010