I'm trying to communicate with an external program which, if executed, will run a terminal interface.
Normally I'll have to provide some inputs (e.g. "1+1") and then read the output of the program (e.g. "2").
Since I need a two-way communication I wasn't able to use popen().
My problem is the following:
Whenever I have a part of the code that asks for inputs, for example containing std::cin >> input I run into the same issue, the read command never exits.
Here I wrote a minimal example, all the child process does is reading the input and repeating it.
When I try to run this code what happens is that I see the first print "Parent says:" and I can provide the input and send it using write. However, when I try to call again the read() function the see the outcome, it never exit.
I've noticed that if I close the pipe that goes from the parent to the child (fd_p2c[1]), then I can read successfully.
This is clearly not what I want, since in my application I'd like to keep both communications open.
Any suggestions on what could be done to fix this problem?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
int status, buf_length;
// Input and output
char buf[256];
char msg[256];
char child_read[256];
int fd_c2p[2]; // file descriptor pipe child -> parent
int fd_p2c[2]; // file descriptor pipe parent -> child
pipe(fd_c2p);
pipe(fd_p2c);
// Spawn a new process with pid
pid_t pid = fork(); // Fork process
if (pid == 0) {
// Child
// Close the unused end of the pipe
if (close(fd_p2c[1]) != 0 || close(fd_c2p[0]) != 0) {
fprintf(stderr, "Faild to close unused end of pipe\n");
exit(1);
}
// Set the comunication
if (dup2(fd_p2c[0], STDIN_FILENO) != 0 ||
dup2(fd_c2p[1], STDOUT_FILENO) != 1 ||
dup2(fd_c2p[1], STDERR_FILENO) != 2) {
fprintf(stderr, "Faild to duplicate the end of the pipes\n");
exit(1);
}
// These two pipe ends are not needed anymore
if (close(fd_p2c[0]) != 0 || close(fd_c2p[1]) != 0) {
fprintf(stderr, "Faild to close unused end of pipe\n");
exit(1);
}
// ask kernel to deliver SIGTERM in case the parent dies
prctl(PR_SET_PDEATHSIG, SIGTERM);
// Moch program
while (1) {
fprintf(stdout, "Parent says: ");
fflush(stdout);
scanf("%s", child_read);
fprintf(stdout, " >> Child repeat: %s\n", child_read);
fflush(stdout);
}
exit(1);
} else {
// Parent
// These two pipe ends are not needed anymore
if (close(fd_p2c[0]) != 0 || close(fd_c2p[1]) != 0) {
fprintf(stderr, "Faild to close unused end of pipe\n");
exit(1);
}
}
// Read output and send input
while (1) {
// Read from child
while (buf_length = read(fd_c2p[0], buf, sizeof(buf) - 1)) {
buf[buf_length] = '\0';
printf("%s", buf);
}
// Enter message to send
scanf("%s", msg);
if (strcmp(msg, "exit") == 0)
break;
// Send to child
write(fd_p2c[1], msg, strlen(msg));
//close(fd_p2c[1]);
}
printf("KILL");
kill(pid, SIGKILL); // send SIGKILL signal to the child process
waitpid(pid, &status, 0);
}
One problem is in the child-process with:
scanf("%s", child_read);
With the %s format there's only three things that will stop scanf from waiting for more input:
Error
End of file
Space
Assuming nothing goes wrong, there will be no errors. And since the parent process keeps the pipe open there will be no end of file. And since the parent process writes only what it itself reads with scanf("%s", ...) there will be no spaces in the data sent.
All in all, the child process will wait indefinitely for scanf to return, which it never will.
Let's call a word what scanf("%s") is able to extract.
This is a contiguous sequence of characters that are not separators (space, tab, new-line...).
The (redirected) standard input of the child reads a word with scanf("%s", child_read);.
This word is known as ended when a separator is read or EOF is reached.
In the parent, write(fd_p2c[1], msg, strlen(msg)); sends a word (and nothing more right after it) because msg is extracted just before as a word.
Note that when you input a word with the keyboard, you also hit the enter key which sends the new-line separator in the standard input. At this time, the terminal makes this line available to scanf(), the word is known as ended and the separator is ignored (in this specific situation, but we could obtain it with fgetc()).
For example, if in the standard input of the parent we input "abc\n",
the parent obtains the word "abc" which is sent as is to the child.
Then the child receives a word starting with "abc" but not ended yet: scanf("%s") is still waiting some other characters after c to make this word longer or a separator or EOF to detect the end of this word.
You can for example send a separator after this word.
// Send to child
write(fd_p2c[1], msg, strlen(msg));
char lf='\n';
write(fd_p2c[1], &lf, 1);
Or maybe it's better to rely on fgets() (instead of scanf("%s")) to obtain a line (not just a word) both in the child and the parent.
By the way, the while/read in the parent looks weird to me.
I would do something like this.
// Read from child
buf_length = (int)read(fd_c2p[0], buf, sizeof(buf) - 1);
if (buf_length <= 0) {
break;
}
If you need a two-ways communication, you could use some unix(7) socket, or several pipe(7)-s, or some fifo(7).
You could use some JSONRPC library. Or XDR (perhaps ONC/RPC/XDR) or ASN/1 for binary communication between heterogeneous computers in a data center, or MPI. If you can use some supercomputer, it probably has proprietary libraries to ease message passing between processes running on different nodes.
Consider using OpenMPI.
I'm trying to communicate with an external program which, if executed, will run a terminal interface.
Maybe you then need some pty(7) with termios(3) ? Then take inspiration from the source code of xterm or of rxvt
You probably need some event loop around a poll(2) before attempting a read(2) (or recv(2)...) or a write(2) (or send(2))
You could find open source libraries (e.g. Glib, libev, ...) to help you, and you certainly should study for inspiration their source code.
Since in general, I wouldn't know the length of the message in that I need to read form fd_c2p, I need to create a look that listens to the pipe till its empty.
To do it is necessary to add the O_NONBLOCK to the file descriptor in the parent as suggested by #some-programmer-dude:
// Parent
// close unused pipe ends
// These two pipe ends are not needed anymore
if (close(fd_p2c[0]) != 0 || close(fd_c2p[1]) != 0) {
fprintf(stderr, "Faild to close unused end of pipe\n");
exit(1);
}
// Add O_NONBLOCK the the fd that reads from the child
int c2p_flags = fcntl(fd_c2p[0], F_GETFL);
fcntl(fd_c2p[0], F_SETFL, c2p_flags | O_NONBLOCK);
Now, when I read the output of the child from the file descriptor fd_c2p[0], it returns an error whenever we attempt to read from an empty file.
Reading the error code in errno should match EWOULDBLOCK.
To know when to stop to read from fd_c2p[0] some knowledge on the output is needed.
This particular reading should stop when the last character of the line when it reaches EWOULDBLOCK and the previous message ended with :.
// Read from child
end_of_message = false;
while (1) {
buf_length = read(fd_c2p[0], buf, sizeof(buf) - 1);
if (buf_length == -1)
{
if (end_of_message && errno == EWOULDBLOCK)
break;
else if (errno == EWOULDBLOCK)
continue;
else {
fprintf(stderr, "reading from pd_c2p returned an error different "
"from `EWOULDBLOCK'\n");
exit(errno);
}
}
buf[buf_length] = '\0';
printf("%s", buf);
end_of_message = buf[buf_length - 1] == ':';
}
This patch solves the problem of reading from the file when one is not sure about how many lines are there before the program asks for inputs.
It should also be safe when the message contains : at any position. To test it, one can reduce the different buffers to a smaller size (e.g. from 256 to 1).
It was also pointed out from by #prog-fh, that in principle one would like to have inputs that contains spaces as well. To accomodate can use fgets instead of scanf:
// Enter message and send it over to the chid process
while (fgets(msg, 256, stdin) != NULL) {
if (msg[strlen(msg)] == '\0')
write(fd_p2c[1], msg, strlen(msg));
else {
fprintf(stderr, "Error encounter while reading input\n");
exit(1);
}
if (msg[strlen(msg) - 1] == '\n')
break;
else
continue;
}
Among the advantages of using fgets there is the fact that the string will keep the newline \n at the end, meaning that there is no need to push an extra character to the write buffer once we are done reading the message.
The complete code is then
#include <cerrno>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
int status, buf_length;
bool end_of_message = false;
int fd_c2p[2]; // file descriptor pipe child -> parent
int fd_p2c[2]; // file descriptor pipe parent -> child
// Input and output
char buf[256];
char msg[256];
char child_read[256];
// We need two pipes if we want a two way comunication.
pipe(fd_c2p);
pipe(fd_p2c);
// Spawn a new process with pid
pid_t pid = fork(); // Fork process
if (pid == 0) {
// Child
// Close the unused end of the pipe
if (close(fd_p2c[1]) != 0 || close(fd_c2p[0]) != 0) {
fprintf(stderr, "Faild to close unused end of pipe\n");
exit(1);
}
// Set the comunications
if (dup2(fd_p2c[0], STDIN_FILENO) != 0 ||
dup2(fd_c2p[1], STDOUT_FILENO) != 1 ||
dup2(fd_c2p[1], STDERR_FILENO) != 2) {
fprintf(stderr, "Faild to duplicate the end of the pipes\n");
exit(1);
}
// These two pipe ends are not needed anymore
if (close(fd_p2c[0]) != 0 || close(fd_c2p[1]) != 0) {
fprintf(stderr, "Faild to close unused end of pipe\n");
exit(1);
}
// ask kernel to deliver SIGTERM in case the parent dies
prctl(PR_SET_PDEATHSIG, SIGTERM);
// Moch Program
while (1) {
fprintf(stdout, "Parent says:");
fflush(stdout);
fgets(child_read, 256, stdin);
fprintf(stdout, " >> Child repeat: %s", child_read);
while (child_read[strlen(child_read) - 1] != '\n') {
fgets(child_read, 256, stdin);
fprintf(stdout, " >> Child repeat: %s", child_read);
}
fflush(stdout);
}
// Nothing below this line should be executed by child process.
// If so, it means that thera has beed a problem so lets exit:
exit(1);
} else {
// Parent
// close unused pipe ends
// These two pipe ends are not needed anymore
if (close(fd_p2c[0]) != 0 || close(fd_c2p[1]) != 0) {
fprintf(stderr, "Faild to close unused end of pipe\n");
exit(1);
}
// Add O_NONBLOCK the the fd that reads from the child
int c2p_flags = fcntl(fd_c2p[0], F_GETFL);
fcntl(fd_c2p[0], F_SETFL, c2p_flags | O_NONBLOCK);
}
// Now, you can write to fd_p2c[1] and read from fd_c2p[0] :
while (1) {
// Read from child
end_of_message = false;
while (1) {
buf_length = read(fd_c2p[0], buf, sizeof(buf) - 1);
if (buf_length == -1)
{
if (end_of_message && errno == EWOULDBLOCK)
break;
else if (errno == EWOULDBLOCK)
continue;
else {
fprintf(stderr, "reading from pd_c2p returned an error different "
"from `EWOULDBLOCK'\n");
exit(errno);
}
}
buf[buf_length] = '\0';
printf("%s", buf);
end_of_message = buf[buf_length - 1] == ':';
}
// Enter message and send it over to the chid process
while (fgets(msg, 256, stdin) != NULL) {
if (msg[strlen(msg)] == '\0')
write(fd_p2c[1], msg, strlen(msg));
else {
fprintf(stderr, "Error encounter while reading input\n");
exit(1);
}
if (msg[strlen(msg) - 1] == '\n')
break;
else
continue;
}
// Check if the user wants to exit the program
if (strcmp(msg, "exit\n") == 0)
break;
}
printf("KILL");
kill(pid, SIGKILL); // send SIGKILL signal to the child process
waitpid(pid, &status, 0);
}
Related
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
int main(void){
//Variables, p[2] for each end of the pipe. nbytes to read pipe return value SUCCESS or FAILURE. pid_t to hold pid of fork process.
// buffer to hold response from the child process.
int p[2], nbytes;
pid_t childpid;
char string[] = "Hello, World!\n";
char buffer[80];
//Declaration of pipe
pipe(p);
//Error handling.
if(((childpid = fork()) == -1) || (pipe(p) == -1))
{
perror("fork");
exit(1);
}
//Child process sends message to paprent.
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(p[0]);
/* Send "string" through the output side of pipe */
write(p[1], string, (strlen(string)+1));
exit(0);
}
else
{
/* Parent process closes up output side of pipe */
close(p[1]);
/* Read in a string from the pipe */
nbytes = read(p[0], buffer, sizeof(buffer));
printf("Received string: %s", buffer);
}
return(0);
}
Output > Received string: #�=zJ
The point of the exercise is to have a child process send a message through a pipe to the parent process and the parent returns the result. This exact code worked the first time I ran it, but then when I tried to run it a second time it started to return seemingly random characters each time. I tried to copy my buffer to another variable but then it was empty. Is the pipe actually not function the way I think it is? What am I doing wrong?
You first create a pipe with pipe(p); and then you create another with ... || (pipe(p) == -1)) Is that deliberate?
2nd Pipe was causing an issue.
You have:
pipe(p);
//Error handling.
if(((childpid = fork()) == -1) || (pipe(p) == -1))
{
perror("fork");
exit(1);
}
This creates two pipes — one in the line pipe(p); and the second in the condition if(((childpid = fork()) == -1) || (pipe(p) == -1)). This is wasteful at best. Moreover, the second pipe is after the fork(), so the parent and child processes don't access the same pipe any more — you overwrote the one created before the fork() which they do share. Test the result of pipe() before calling fork() and remove the extra condition in the if test:
if (pipe(p) != 0)
{
perror("pipe");
exit(1);
}
if ((childpid = fork()) < 0)
{
perror("fork");
exit(1);
}
Get used to testing for errors and writing appropriate code to handle them. It will be a major part of your life as a C programmer.
Later on in the code, you have:
{
/* Parent process closes up output side of pipe */
close(p[1]);
/* Read in a string from the pipe */
nbytes = read(p[0], buffer, sizeof(buffer));
printf("Received string: %s", buffer);
}
You need to heed the value of nbytes. Since it is an int, you could use:
printf("Received %d bytes: [%.*s]\n", nbytes, nbytes, buffer);
This limits the output to what was read, and reports 0 if that's what it gets. I suppose you should also check for -1 in nbytes before using it in the printf() statement:
if (nbytes < 0)
{
fprintf(stderr, "failed to read from pipe descriptor %d\n", p[0]);
// Or perror("read");
// Should you exit here with a non-zero status?
}
else
printf("Received %d bytes: [%.*s]\n", nbytes, nbytes, buffer);
Note: errors are reported on stderr; perror() does that automatically.
The problem is that you create two pipes when you really only need to check the first for errors:
// Declaration of pipe
if(pipe(p) == -1) { // check for error here
perror("pipe");
exit(1);
}
// Error handling.
if((childpid = fork()) == -1) { // and don't create another pipe here
perror("fork");
exit(1);
}
You should also check the return values from write and read. They may not write or read the full string in one go.
I am working on a program where the main program forks itself and the child process calls exec. I have set it up so that the parent process has 2 pipes StdOutPipe and StdInPipe, and the child process calls dup so that stdout writes to the StdOutPipe and stdin reads from StdInPipe. Then the parent process calls wait, after which i would like to read the entirety of the StdOutPipe into a buffer. I know you can do so by reading one character at a time, but is there a faster way to do so?
For performance reasons, one typically reads a chunk at a time, not a character at a time.
Loop,
Attempt to enlarge the buffer so it can fit CHUNK_SIZE more bytes.
If an error occurred,
Fail.
Attempt to read CHUNK_SIZE bytes from the pipe into the unused part of the buffer.
If an error occurred,
Fail.
If EOF was reached,
Break.
Increased the total number of bytes read by the number of bytes read.
A pipe is basically a byte stream which means:
There's no concept of messages or message boundaries with pipes
The process reading from a
pipe can read blocks of data of any size, regardless of the size of blocks written by
the writing process
A read from a pipe is usually blocked until atleast a byte is written to the pipe.
That said, here's how i would implement your issue.
Create two pipes, stdinpipe and stdoutpipe
Do a fork
Parent process should close the write end of the pipes and sit in a
loop, waiting until data is written to pipe
Child process should close the read end of the pipes and duplicate
STDOUT to stdoutpipe and STDIN to stdinpipe
Child process can then do an exec.
Sample code:
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#define STDPIPE_BUFFER_SIZE 4096
#define ARGV_SIZE 3
int main()
{
// Stdoutpipe and stdint pipe
int stdoutpipe[2], stdinpipe[2], stdin_char_count, stdout_char_count, stdout_read, stdin_read;
pid_t pid;
char stdinbuffer[STDPIPE_BUFFER_SIZE], stdoutbuffer[STDPIPE_BUFFER_SIZE];
char *argv[ARGV_SIZE]; // arguments to exec
if (pipe(stdinpipe) == -1 || pipe(stdoutpipe) == -1)
exit(1); // error occurred
// Fork and exec
switch (pid = fork())
{
case -1:
exit(1); // error
case 0:
// child close the read end of both pipes
if (close(stdinpipe[0]) == -1 || close(stdoutpipe[0]) == -1)
exit(1);
// have the pipes as the new STDIN and STDOUT
if (dup2(stdinpipe[1], STDIN_FILENO) == -1 || dup2(stdoutpipe[1], STDOUT_FILENO) == -1)
exit(1);
argv[0] = "/usr/bin/ssh"; // replace with your own program [ssh -V in my case]
argv[1] = "-V";
argv[2] = NULL;
execve(argv[0], argv, NULL);
exit(1); // if we get here something horribly bad happened
default:
// parent process
stdin_char_count = 0;
stdout_char_count = 0;
// parent close write end of both pipes
if (close(stdinpipe[1]) == -1 || close(stdoutpipe[1]) == -1)
exit(1);
for (;;)
{
stdin_read = read(stdinpipe[0], stdinbuffer, STDPIPE_BUFFER_SIZE);
stdout_read = read(stdinpipe[0], stdinbuffer, STDPIPE_BUFFER_SIZE);
if (stdin_read == 0 && stdout_read == 0)
{
stdinbuffer[stdin_char_count] = '\0';
stdoutbuffer[stdout_char_count] = '\0';
break;
}
if (stdin_read == -1 && stdout_read == -1)
exit(1); // we cant recover from this
stdin_char_count += stdin_read;
stdout_char_count += stdout_read;
}
printf("%s\n", stdoutbuffer);
wait(NULL);
}
}
source: https://man7.org/linux/man-pages/man2/pipe.2.html
You can convert the pipe into an ordinary stream and then use whatever function you find convenient to read the data. Here, getdelim() can be used to read all text up to a NUL byte which need not be sent over the pipe. Error checking is partially omitted for brevity.
Also be aware that if you want to continue interacting directly with the pipe even after opening the stream, you'll probably want to disable buffering on the stream.
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void) {
int fds[2];
if(pipe(fds) == -1) {
perror("Failed to create pipe");
exit(EXIT_FAILURE);
}
const pid_t pid = fork();
if(pid == -1) {
perror("Failed to fork");
exit(EXIT_FAILURE);
}
if(!pid) {
close(fds[0]);
const char *const msg = "Hello, world!";
if(write(fds[1], msg, strlen(msg)) == -1) {
perror("Failed to write");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
close(fds[1]);
FILE *const stream = fdopen(fds[0], "r");
if(!stream) {
perror("Failed to create stream");
exit(EXIT_FAILURE);
}
char *text = NULL;
assert(wait(NULL) != -1);
getdelim(&text, &(size_t){0}, '\0', stream);
fclose(stream);
assert(text);
puts(text);
free(text);
}
I am in a scenario where I have to write a program that creates two processes. The father process
opens a text file for reading. It is assumed that the file is composed of words formed of
alphabetic characters separated by spaces. The child process enters a word on the keyboard. The
father process looks for the word in the file, and passes to the child the value 1 if the word is in
the file, and 0 otherwise. The son displays the result.
Here I think used the tubes for communication between these processes.
However, this communication seems to me difficult.
Does this ordering:
process father-process son-process father-process son is possible?
Attaching a simple pipe program for basic understanding. One can modify according to her needs.
/* simple_pipe.c
Simple demonstration of the use of a pipe to communicate
between a parent and a child process.
Usage: simple_pipe "string"
The program creates a pipe, and then calls fork() to create a child process.
After the fork(), the parent writes the string given on the command line
to the pipe, and the child uses a loop to read data from the pipe and
print it on standard output.
*/
#include <sys/wait.h>
#include "tlpi_hdr.h"
#define BUF_SIZE 10
int
main(int argc, char *argv[])
{
int pfd[2]; /* Pipe file descriptors */
char buf[BUF_SIZE];
ssize_t numRead;
if (argc != 2 || strcmp(argv[1], "--help") == 0)
usageErr("%s string\n", argv[0]);
if (pipe(pfd) == -1) /* Create the pipe */
errExit("pipe");
switch (fork()) {
case -1:
errExit("fork");
case 0: /* Child - reads from pipe */
if (close(pfd[1]) == -1) /* Write end is unused */
errExit("close - child");
for (;;) { /* Read data from pipe, echo on stdout */
numRead = read(pfd[0], buf, BUF_SIZE);
if (numRead == -1)
errExit("read");
if (numRead == 0)
break; /* End-of-file */
if (write(STDOUT_FILENO, buf, numRead) != numRead)
fatal("child - partial/failed write");
}
write(STDOUT_FILENO, "\n", 1);
if (close(pfd[0]) == -1)
errExit("close");
_exit(EXIT_SUCCESS);
default: /* Parent - writes to pipe */
if (close(pfd[0]) == -1) /* Read end is unused */
errExit("close - parent");
if (write(pfd[1], argv[1], strlen(argv[1])) != strlen(argv[1]))
fatal("parent - partial/failed write");
if (close(pfd[1]) == -1) /* Child will see EOF */
errExit("close");
wait(NULL); /* Wait for child to finish */
exit(EXIT_SUCCESS);
}
}
Have a look on more examples here on Chapter-44 The Linux Programming Interface.
Keep this book on your table or e-book on you computer, it's a bible for Linux programming.
As explained in this answer, I'd be expecting the reader process to catch the EOF right after the writer process closes all related file descriptors.
But that doesn't happen and this program ends up stuck in an endless loop.
Parent waits for it's child to finish & child waits for EOF signalizing closed pipe.
Why the reader process doesn't receive EOF?
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <wait.h>
#define STRING_TO_SEND "Hello, world!\n"
int main() {
int fd[2], i = 0;
__pid_t pid;
char _char;
ssize_t nbytes;
pipe(fd);
pid = fork();
if (pid == -1) {
// Error
perror("Error forking!");
return EXIT_FAILURE;
} else if (pid == 0) {
// Child
close(fd[1]);
while ((nbytes = read(fd[0], &_char, 1)) != EOF) {
if (nbytes == 0)
continue;
putchar(_char);
}
close(fd[0]);
} else {
// Parent
close(fd[0]);
for(;;) {
_char = STRING_TO_SEND[i++];
write(fd[1], &_char, 1);
if (_char == '\0')
break;
}
close(fd[1]);
close(STDOUT_FILENO);
while (wait(NULL)>0) {}
}
return 0;
}
You simply misunderstood the "end of file" indication of read() which simply means nothing more to read for read() (read() returns 0 in that case). But read() doesn't actually return the value EOF. So your condition should be:
while ((nbytes = read(fd[0], &_char, 1)) > 0) {
Also __pid_t is an internal type of your C library. You shouldn't use that; just use pid_t.
See read(2)'s man page for details.
EOF is a constant usually defined to -1 that stdio (the C library buffering layer around the raw system calls) uses to signal end of file in functions like getchar() which conflate the returned character with an end-of-file signal.
read signals end-of-file by simply returning 0. Note that it can also return -1 if there's an error (e.g., you can get EINTR if the read is interrupted by a signal handler before it read anything).
Consequently, what you want is something like:
while ((nbytes = read(fd[0], &_char, 1)) > 0){ /*...*/ }
if (0>nread) { /*report error (or maybe repeat if it's EINTR)*/ }
Manpages (read(2)) or the POSIX spec for read document all this.
I'm working on some code involving pipes. The idea is that I'm supposed to have a process looping indefinitely and add data to the pipe as it comes (I'm testing this by reading a file, and going line by line in a while loop).
If I set the other process (the one that reads the pipe) to sleep so the entire file is read I have no problems and get all the file in the output. As soon as I remove the sleep (so now the 2 processes start simultaneously with the 2nd process reading the information off the pipe as it comes), my code goes straight to the else block of my code below and I never see any actual output. What am I doing wrong?
close(pipe[1]);
sleep(5);
while (1) {
nbytes = read(pipe[0], buffer, 200);
if(errno != EWOULDBLOCK) {
printf("%s", buffer);
}
else {
printf("I am not blocked here\n");
sleep(1);
}
}
Thanks
Two things:
did you make pipe[0] non-blocking? It'll be something like int nbio=1; ioctl(pipe[0], FIONBIO, &nbio);
you're checking for error wrong.
if(nbytes > 0) {
/* you may need to null-terminate the input buffer prior to display */
buffer[nbytes] = '\0';
printf("%s", buffer);
}
else if(errno == EWOULDBLOCK) {
printf("I am not blocked here\n");
sleep(1);
}
else {
printf("some other error occurred - if nbytes == 0, then it's EOF.\n");
}
probably errno is EWOULDBLOCK the first time through, and then doesn't get updated on successful read, so it looks like EWOULDBLOCK again.