Using the polled function with buffered streams

I am trying to implement a client-server communication system using the poll function in C. The flow is as follows:

  • The main program opens the subprocess
  • A child process calls a function execto executesome_binary
  • Parent and child send messages to each other in turn, each sent message depends on the last message received.

I tried to implement this with help poll, but ran into problems because the child process was buffering its output, causing my calls pollto time out. Here is my code:

int main() {
char *buffer = (char *) malloc(1000);
int n;

pid_t pid; /* pid of child process */

int rpipe[2]; /* pipe used to read from child process */
int wpipe[2]; /* pipe used to write to child process */
pipe(rpipe);
pipe(wpipe);

pid = fork();
if (pid == (pid_t) 0)
{
    /* child */

    dup2(wpipe[0], STDIN_FILENO);
    dup2(rpipe[1], STDOUT_FILENO);
    close(wpipe[0]); close(rpipe[0]);
    close(wpipe[1]); close(rpipe[1]);
    if (execl("./server", "./server", (char *) NULL) == -1)
    {
        fprintf(stderr, "exec failed\n");
        return EXIT_FAILURE;
    }       
    return EXIT_SUCCESS;
}
else
{
    /* parent */

    /* close the other ends */
    close(wpipe[0]);
    close(rpipe[1]);

    /* 
      poll to check if write is good to go 
                This poll succeeds, write goes through
        */
    struct pollfd pfds[1];
    pfds[0].fd = wpipe[1];
    pfds[0].events = POLLIN | POLLOUT;
    int pres = poll(pfds, (nfds_t) 1, 1000);
    if (pres > 0)
    {
        if (pfds[0].revents & POLLOUT)
        {
            printf("Writing data...\n");
            write(wpipe[1], "hello\n", 6);
        }
    }

    /* 
        poll to check if there something to read.
        This poll times out because the child buffers its stdout stream.
    */
    pfds[0].fd = rpipe[0];
    pfds[0].events = POLLIN | POLLOUT;
    pres = poll(pfds, (nfds_t) 1, 1000);
    if (pres > 0)
    {
        if (pfds[0].revents & POLLIN)
        {
            printf("Reading data...\n");
            int n = read(rpipe[0], buffer, 1000);
            buffer[n] = '\0';
            printf("child says:\n%s\n", buffer);
        }
    }

    kill(pid, SIGTERM);
    return EXIT_SUCCESS;
}
}

Server code is simple:

int main() {
    char *buffer = (char *) malloc(1000);

    while (scanf("%s", buffer) != EOF)
    {
        printf("I received %s\n", buffer);
    }   
    return 0;
}

How to prevent pollcalls from timeout due to buffering?

EDIT:

, , exec ed , .. - unix, , cat ls.

0
2

, , ; , , :

while (1) { // simplistic event loop!
   int status=0;
   if (waitpid(pid, &status, WNOHANG) == pid)
      { // clean up, child process has ended
        handle_process_end(status);
        break;
      };
   struct pollpfd pfd[2];
   memset (&pfd, 0, sizeof(pfd)); // probably useless but dont harm
   pfd[0].fd = rpipe[0];
   pfd[0].events = POLL_IN;
   pfd[1].fd = wpipe[1];
   pfd[0].event = POLL_OUT;
   #define DELAY 5000 /* 5 seconds */
   if (poll(pfd, 2, DELAY)>0) {
      if (pfd[0].revents & POLL_IN) {
         /* read something from rpipe[0]; detect end of file; 
            you probably need to do some buffering, because you may 
            e.g. read some partial line chunk written by the child, and 
            you could only handle full lines. */
      };
      if (pfd[1].revents & POLL_OUT) {
         /* write something on wpipe[1] */
      };
   }
   fflush(NULL);
} /* end while(1) */

, , . , ( ) , .... ( , isatty).

, , , , , stdout , ( stdin-), : , , (.. ), , (.. ). , " " " ".

Advanced Linux Programming, , !

, : , stdout, . waitpid poll

, , write ( ) read . , . POSIX PIPE_MAX.... . write. , , read write, PIPE_MAX.

: poll , , poll ( !) ( ) ! "rpipe[0] readable", read 324 , , poll , "wpipe[1] writeable", write 10 , poll , "rpipe[0] ", read 110 , , poll "rpipe[0] readable", read 4096 .. .. , : poll , "wpipe[1] writeable", write 1000 , , poll , "rpipe[0] ..

NB: ( "" ), , . , ( , ; ), , (2) (2), pipe (7), poll (2) ( read write POLL_IN POLL_OUT revents poll)), BTW, , fflush .

+1

. "stdout" , :

printf("I received %s\n", buffer);
fflush(stdout);

POLLOUT ( POLLERR):

pfds[0].fd = rpipe[0];
pfds[0].events = POLLIN | POLLERR;

:

$ ./main
Writing data...
Reading data...
child says:
I received hello

, poll() , (, ).

+2

All Articles