Программа с именованными каналами иногда работает, иногда дает сбой

#c #linux #named-pipes

#c #linux #именованные каналы

Вопрос:

Здравствуйте, я пытаюсь создать программу на c, которая использует именованные каналы для связи с другой программой, но если я запускаю ее более одного раза, большую часть времени она терпит неудачу, иногда работая отлично, хотя я ничего не меняю между тестами. Вот код для arbitro.c программа, которую я выполняю первой

 #include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <fcntl.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <signal.h> 

int main(int argc, char *argv[])
{
    int fd,id1,cont_pront=0,i=0; 
    char nomejog[40]="",instrucao[40]="";
    // FIFO file path 
        char * myfifo = "myfifo";
    // Creating the named file(FIFO) 
        mkfifo(myfifo, 0666);
do{
    fd = open(myfifo,O_RDONLY); 
        if(fd == -1){
            fprintf(stdout, "Erro a abrir.n");
        }
        // First open in read only and read 
    for(int i=0;i<2;i  ){
        read(fd, nomejog, 40); //Recebe o nome do jogador
        read(fd, amp;id1,sizeof(id1)); //Recebe o id do primeiro jogador
        fprintf(stdout, "Nome: %s -» %dn", nomejog,id1);
        cont_pront  ;
    }
    fprintf(stdout, "Nº: %dn", cont_pront);

    //Now open in write mode and write
    fd = open(myfifo,O_WRONLY);
    if(fd == -1){
        fprintf(stdout, "Erro a abrir.n");
    }
    if(cont_pront >= 2){
        cont_pront = -1;
    }
    write(fd, amp;cont_pront, sizeof(int));
    close(fd);


// optind is for the extra arguments 
// which are not parsed 
for(; optind < argc; optind  ){
    if(i == 0){
        printf("Duração do campeonato: %sn", argv[optind]);
    }else{
    if(i == 1){
        printf("Tempo de espera: %sn", argv[optind]);
    }
    }

    i  ;
}

}while(strcmp(instrucao,"exit") != 0);
    return 0;
}
 

и вот код для cliente.c

 #include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <fcntl.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <signal.h> 

int main(int argc, char *argv[]){
    int fd1,cont_pront=0;
    char nomejog[40]="";
    // FIFO file path 
        char * myfifo = "myfifo";
    // Creating the named file(FIFO) 
        mkfifo(myfifo, 0666);


    // Open FIFO for write only 
        fd1 = open(myfifo, O_WRONLY); 
        //Enviar o nome do jogador ao arbitro
        for(int i=0;i<2;i  ){

        write(fd1, nomejog,strlen(nomejog) 1); //Envia o nome do jogador já pronto
        write(fd1,amp;i, sizeof(int)); //Envia o id
        strcpy(nomejog,"pedro");
    }
    close(fd1);

    //Receber quantos jogadores estão prontos
    fd1 = open(myfifo, O_RDONLY);

    read(fd1, amp;cont_pront, sizeof(int)); //Recebe o nome do jogador

    if(cont_pront == -1){
        //Tem jogadores necessários para começar o jogo
        fprintf(stdout,"Existem jogadores suficientes, o campeonato vai ser iniciado...n");
        execl("GAMEDIR/game01","GAMEDIR/game01", NULL);
    }else{
        //Ainda não tem jogadores suficientes para começar o jogo
        fprintf(stdout,"Nao tem jogadores suficientes para comecar o campeonato.n");
    }
    close(fd1);
return 0; 
}
 

если все идет хорошо, это должно говорить о том, что игроков достаточно, и игра выполняется, но по какой-то причине иногда все повторяется, отправляя больше игроков пустыми, или клиент останавливается на полпути выполнения или даже не отправляет правильных игроков в первую очередь

Комментарии:

1. Первое, что нужно сделать, это проверить возвращаемые значения всех ваших системных вызовов, и perror() если они завершаются неудачей. Это поможет сузить возможную причину сбоя и должно быть сделано в любом случае.

2. Одна ошибка заключается в том, что клиент записывает переменное количество байтов для nomejog (1 в первый раз, 6 во второй раз), а затем 4 байта для целого i числа. Ядро не гарантирует, что отдельные записи будут разделены, поэтому, когда сервер пытается прочитать 40 байт, он может прочитать все 15 байт, nomejog а затем оставшиеся чтения сообщат о конце файла (который вы не проверяете) и оставят их буферы неинициализированными. Вам нужно будет изменить свой протокол, чтобы клиент и сервер договорились о том, сколько байтов ожидается для отправки и получения для каждого фрагмента данных.