// gcc -Wall -Wextra servernb.c -o servernb #include #include #include #include #include #include #include #include #define FIFO_PATH "/tmp/myfifo" // Use read(2) NON-blocking ... int main() { int fd = -1; fd_set readfds; int nsel; char buf[80] = { 0 }; if (unlink (FIFO_PATH) < 0 && errno != ENOENT) { perror ("unlink"); exit (1); } if (mkfifo(FIFO_PATH, 0600) < 0) { fprintf(stderr, "Could not create fifo %s: %s\n", FIFO_PATH, strerror(errno)); return -1; } fd = open(FIFO_PATH, O_RDONLY | O_NONBLOCK); // open() does not block printf("fd = %d\n", fd); if (fd < 0) { fprintf(stderr, "Could not open fifo %s: %s\n", FIFO_PATH, strerror(errno)); return -1; } #if 0 // disabled: non-blocking read if (fcntl(fd, F_SETFL, O_RDONLY) == -1) // pragmatic fprintf(stderr, "fcntl F_SETFL: %s\n", strerror(errno)); #endif int flags = fcntl(fd, F_GETFL); if (flags == -1) fprintf(stderr, "fcntl F_GETFL: %s\n", strerror(errno)); printf("flags = 0%o\n", flags); while(1) { printf("Calling select() ... "); fflush(stdout); FD_ZERO (&readfds); FD_SET (fd, &readfds); /* see comment in serverb.c ... */ /* see comment in serverb.c ... */ /* select(2) still blocks after returning from read(2) (which happened when data became available) after the pipe became empty again. */ nsel = select (fd + 1, &readfds, NULL, NULL, NULL); printf ("returned %d\n", nsel); printf("Reading ...\n"); ssize_t status = 0; while (1) { // allow me to reset errno and inspect status ... errno = 0; /* see comment in serverb.c ... */ /* we arrive here when data becomes available (and the write end is open) */ status = read(fd, buf, sizeof(buf)); printf("status = %ld, errno = %d\n", status, errno); if (status == 0) { // the write end of the fifo has been closed (EOF) /* we arrive here when the write end is closed (after the write end had been opened and data became available) */ #if 1 // file descriptor must be refreshed; otherwise select(2) will not block int fd2; if ((fd2 = open (FIFO_PATH, O_RDONLY | O_NONBLOCK)) < 0) { close(fd); perror ("open"); exit (1); } /* see comment in serverb.c ... */ close(fd); // do not close before another file descriptor is available fd = fd2; // required (fd2 is opened before fd is closed) printf("fd = %d - refreshed\n", fd); #endif #if 0 // disabled: non-blocking read if (fcntl(fd, F_SETFL, O_RDONLY) == -1) // pragmatic fprintf(stderr, "fcntl F_SETFL: %s\n", strerror(errno)); #endif int flags = fcntl(fd, F_GETFL); if (flags == -1) fprintf(stderr, "fcntl F_GETFL: %s\n", strerror(errno)); printf("flags = 0%o\n", flags); break; } if (status > 0) { /* we arrive here when data becomes available (after the write end was opened) */ if (write(1, buf, status) < 0) { fprintf(stderr, "Error sending message: '%s': %s\n", buf, strerror(errno)); } if (buf[status - 1] != '\n') { write(1, "\n", 1); } if (strncasecmp(buf, "quit", 4) == 0) { close(fd); remove(FIFO_PATH); exit (0); } } if (status < 0) { if (errno == EAGAIN) { // added for the non-blocking case! /* we arrive here when the pipe becomes empty (after data became available when the write end was opened) */ printf("Got EAGAIN ...\n"); // would show up in case write end is not closed immediately errno = 0; break; } /* An error occurred, bail out */ close(fd); perror("read"); exit (1); } } // end while(1) read } // end while(!done) select close(fd); remove(FIFO_PATH); return 0; } //=====