Сломанные каналы в программе C pipe(), fork(), exec()

Мне нужно написать простую программу: будет Родитель и несколько программ [дочерних] (запускаются через execl в Родителе). Дети общаются друг с другом следующим образом: Ребенок I чувствует Родителю номер J, Родитель посылает сообщение (что-то вроде -- «вам есть сообщение») J, J отправляет Родителю номер K и т. д. и т. д.

И есть проблема - моя программа (проверенная командой strace) пытается отправить сообщение дочернему элементу, и возникает ошибка обрыва канала.

Буду признателен, если кто-нибудь просмотрит код и скажет мне, что не так:

Вот код:

/**
 * Arbiter zabawy w Losia
 *

 wersja: Alfa 3b
 początek edycji 25.01.2009
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "err.h"

pid_t pid;
FILE *a;

int main ()
{
    // my N players
    int N;
    N = 10;
    //write -- writing from parent to child 
    //read -- reading from child
    int rurka_write[N+1][2]; 
    int rurka_read[N+1][2];
    //initiation of N players
    int i;
    for(i = 1; i <= N; i++)
    {
        //tworze lacza
        if (pipe(rurka_write[i]) == -1)
            printf("wystapil blad przy rurce %d\n", i);
        if (pipe(rurka_read[i]) == -1)
            printf("wystapil blad przy rurce %d\n", i); 
    }
    for(i = 1; i <= N; i++)
    {
        switch(pid = fork())
        {
            case -1: 
                printf("wystapil blad przy forkowaniu");
            case 0:
                printf("potomek numer %d\n", i);
                if (close(rurka_write[i][1]) == -1)
                    printf("zle zamykanie");
                if (close(rurka_read[i][0]) == -1)
                    printf("zle zamykanie");

                //closing useless descriptors
                int j;
                for(j = 1; j <= N; j++)
                {
                    if (j != i)
                    {
                        close(rurka_read[j][0]);
                        close(rurka_read[j][1]);
                        close(rurka_write[j][0]);
                        close(rurka_write[j][1]);
                    }
                }   

                char str_N[20];
                char str_i[20];
                char str_0[20];
                char str_1[20];

                sprintf(str_N, "%d", N);
                sprintf(str_i, "%d", i);
                sprintf(str_0, "%d", rurka_write[i][0]);
                sprintf(str_1, "%d", rurka_read[i][1]);

                printf("%d Executing execl\n", i);
                execl("./ucz", str_N, str_i, str_0, str_1, NULL);
                printf("execl executed\n");
//              execv("./ucz", str_N, str_i, str_0, str_1, NULL);
                //exit(0);
            default:
                //closing useless pipes
                if (close(rurka_read[i][1]) == -1)
                    printf("zle zamykanie rurki do czytania z potomkna\n");
                if (close(rurka_write[i][0]) == -1)
                    printf("zle zamykanie rurki do pisania do potomka\n");
        } //end of switch

    } //end of for
    //if I am in parent, I'm starting the game
    if (pid != 0)
//  delay(100);
    {
        printf("PLAY\n");
        int l = 1;
        while(l > 0)
        {
            printf("sending to player %d\n", l);
            a = fdopen(rurka_write[l][1], "w");
            printf("sending: Wake up");
            fprintf(a, "Wake up\n");
            printf("flushing");
            fflush(a);
            char k[20];
            printf("reading");
            read(rurka_read[l][0], k, 20);
            l = k;
        }
    }
}

person Community    schedule 25.01.2009    source источник
comment
Вы должны опубликовать свою ошибку вместе с кодом.   -  person Kieveli    schedule 26.01.2009
comment
Я думаю, что в вашей программе есть ошибка: я думаю, вы хотите закончить свои операторы case словом «break;».   -  person strager    schedule 26.01.2009
comment
Я действительно не могу ответить, не видя, что ucz делает со своими параметрами. Кроме того, вы должны выйти/прервать выполнение после exec* (поскольку exec не должен возвращаться, если не произошла ошибка, и обычно это мешает вашему потоку кода)   -  person Hasturkun    schedule 26.01.2009


Ответы (2)


Помимо того факта, что вы не заканчиваете свои дела на break (как заметил Стрейджер), основная проблема заключается в утверждении l = k;. Обратите внимание, что k — это char[20], и при назначении int вы не назначаете содержимое k l. Вместо этого l будет содержать (значение) указатель на массив. Вам нужно будет сделать что-то другое здесь, чтобы получить значение, которое находится в массиве; что именно зависит от того, что ucz отправляет обратно.

После исправления этого и создания собственного ucz программа работает без проблем. Конечно, может быть и другая проблема в вашей версии ucz.

person mweerden    schedule 26.01.2009

Насчет ./ucz -- принимает 4 параметра -- 1-й -- количество игроков, 2-й -- номер игрока, 3-й -- номер дескриптора для чтения из родителя, 4-й -- номер дескриптора для записи в родителя.

Добавление exit(0), return(0), break после exec (или в конце case: 0) не помогает.

person Community    schedule 26.01.2009