1

I've written a engine for the game "draughts" some time ago and now I want to write a program that communicates with two of those engines via some protocol. In the end I hope to have something similar to the UCI-protocol which is widely known among programmers of chess engines.

The engine is supposed to receive all the commands via stdin and sends it's response via stdout.

I've created some dummy engine to test this with some testing before the if-statement to see if the engine receives anything at all.

int main(){

     std::cerr<<"MainEngine"<<std::endl;
            while (!std::cin.eof()) {
                std::string current;
                std::getline(std::cin, current);
                std::cerr<<"FromMain:"<<current<<std::endl;
                if (current == "init") {
                    initialize();
                    std::cout << "ready" << "\n";
                } else if (current == "hashSize") {
                    std::string hash;
                    std::getline(std::cin, hash);
                    setHashSize(1u << std::stoi(hash));
                } else if (current == "position") {
                    std::string position;
                    std::getline(std::cin, position);
                } else if (current == "move") {
                    std::string move;
                    std::getline(std::cin, move);
                }
            }

    return 0
    }

and here is my attempt at the communication-part using pipes

 struct Interface {
        enum State {
            Idle, Ready, Searching
        };
        const int &engineRead1;
        const int &engineRead2;
        const int &engineWrite1;
        const int &engineWrite2;
        State oneState;
        State twoState;

        void initEngines();

        void writeMessage(const int &pipe, const std::string &message);

        void processInput(const int &readPipe);

        Interface &operator<<(const std::string message);

    };

    void Interface::processInput(const int &readPipe) {
        std::string message;
        char c;
        while ((read(readPipe, &c, sizeof(char))) != -1) {
            if (c == '\n') {
                break;
            } else {
                message += c;
            }
        }
        if (message == "ready") {
            std::cout << "ReadyEngine" << std::endl;
        }
    }

    void Interface::writeMessage(const int &pipe, const std::string &message) {
        write(pipe, (char *) &message.front(), sizeof(char) * message.size());
    }


    int main(int argl, const char **argc) {
        int numEngines = 2;
        int mainPipe[numEngines][2];
        int enginePipe[numEngines][2];

        for (auto i = 0; i < numEngines; ++i) {
            pipe(mainPipe[i]);
            pipe(enginePipe[i]);


            auto pid = fork();

            if (pid < 0) {
                std::cerr << "Error" << std::endl;
                exit(EXIT_FAILURE);
            } else if (pid == 0) {
                dup2(mainPipe[i][0], STDIN_FILENO);
                close(enginePipe[i][1]);
                dup2(enginePipe[i][1], STDOUT_FILENO);
                close(mainPipe[i][0]);
                execlp("./engine", "engine", NULL);
            }
            close(enginePipe[i][0]);
            close(mainPipe[i][1]);

            std::string message = "init\n";
            Interface inter{enginePipe[0][0], enginePipe[1][0], mainPipe[0][1], mainPipe[1][1]};
            inter.writeMessage(inter.engineWrite1, message);
            inter.writeMessage(inter.engineWrite2, message);

            int status;
            for (int k = 0; k < numEngines; ++k) {
                wait(&status);
            }
        }
    }

I am creating two child-process one for each engine. In this test I simply send "init\n" to each of the engine and would expect the child processes to print "FromMain: init". However, I am only getting the output "MainEngine" from one of the child-processes.

This is my first attempt at using pipes and I dont know where I messed up. I would appreciate some tips/help on how to properly setup the communication part.

XPenguen
  • 163
  • 1
  • 8
  • 2
    See: [Why !.eof() inside a loop condition is always wrong.](https://stackoverflow.com/q/5605125/9254539) You will also want to review [Why is iostream::eof inside a loop condition considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – David C. Rankin Oct 25 '19 at 22:20
  • Thx for pointing this out !!! – XPenguen Oct 25 '19 at 22:21
  • You were lucky that was limited to your *dummy engine* `:)` – David C. Rankin Oct 25 '19 at 22:22

1 Answers1

1
                close(enginePipe[i][1]);
                dup2(enginePipe[i][1], STDOUT_FILENO);

You're closing a pipe and then trying to dup it. This doesn't work.

            close(enginePipe[i][0]);
            close(mainPipe[i][1]);

            std::string message = "init\n";
            Interface inter{enginePipe[0][0], enginePipe[1][0], mainPipe[0][1], mainPipe[1][1]};

And you're closing these pipes then trying to use them too. And making inter with all of the pipes each iteration through, instead of each only once.

I'd advise you to do something simple with two processes and one pipe, before trying complicated things like this with three processes and four pipes.