// Some code for initialization
int fd[2];
pipe(fd);
int k = fork();
if (k == 0) { // Child
dup2(fd[1], fileno(stdout));
execl("someExecutable", NULL); // The executable just printfs one line
}
else if (k > 0) { // Parent
wait(&status);
while (read(fd[0], buffer, 1) > 0) {
printf("%s", buffer);
}
}
I omitted error checking.
First, if my executable has printf("some line\n");, my output on screen looks like s?9o?9m?9e?9 ?9l?9i?9n?9e?9. Why are there these random characters in between?
Second, my reading never ends. The read end of the pipe should've closed when the executable ended right?
Thank you.
You're printing binary data. The following
while (read(fd[0], buffer, 1) > 0) {
printf("%s", buffer);
}
Will print until it gets a NULL ie '\0'. Try this instead
while (read(fd[0], buffer, 1) > 0) {
printf("%.*s", 1, buffer);
}
This code might help illustrate the point about printf and null terminated strings...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main(void) {
srand(time(NULL));
size_t n = 0;
//First we create some random data.
//Lets assume this is our binary stream
char *str_cpy = malloc(1024);
n = 0;
while(n++ < 1024) {
str_cpy[n] = rand() % 255;
}
//We have a known string we want to print
const char *str = "foobar";
printf("%s\n", str);
memcpy(str_cpy, str, 6);//Ooops: forgot to copy the null terminator
size_t str_len = strlen(str_cpy);
// This is unlikely to print 6
printf("%zu\n", str_len);
//This is undefined behavior
printf("%s\n", str_cpy);
free(str_cpy);
return 0;
}
You have to pass a (pointer to) null-terminated string to %s format specifier in printf().
To print one character, using %c is good.
while (read(fd[0], buffer, 1) > 0) {
printf("%c", *buffer);
}
If your buffer is declared as char buffer, then pass a pointer to it in read(), if it is declare as buffer[], then you may want to pass the size as the parameter instead of 1, as you are already checking for the status for read() which should return the number of bytes read, if successful. Now change printf("%c"...) or printf("%s"...), accordingly.
Related
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
char buf[10];
int ret;
while(1) {
ret = read(0, buf, sizeof buf);
printf("%s\n", buf);
}
return(0);
}
Basically, this is what happens:
$ gcc -Wall above.c
$ ./a.out
h
h
#
a
a
&
^C
$
How do I make it so that this special character is not printed? I'm unsure how to fix this. I tried making buf[10] = '\0' but I still get the same error.
You have several errors, why don't use the return value of read?
Simply you can use it in a "%.*s" format specifier, like in
printf("%.*s\n", ret, buf);
but....
you have to check that ret < 0 for errors.
you have to check that ret == 0 for End of file condition.
read(2) never terminates the sequence of characters read with a \0 char, so you cannot use any str* function on it (I used the trick of printing only the first ret chars because the ret variable tells me there are not more, so I don't get behind the last character read) but this approach will eat all the characters read after an actual \0 in the input file (or in the buffer), up to the ret-esim char. That is because the %*s format stops before the specified ret value if it finds the string terminator null char.
It is better to use write(2) or fwrite(2) with read(2), as in:
write(1, buffer, ret);
As read(2), write(2) doesn't treat \0 as a string terminator, and case you have some \0 chars in the buffer, it will print them, as if they were normal characters. This is important if you do want verbatim output from input (as in cat(1) command)
read() does not zero terminate anything. It is a function that is used to read any bytes from a file descriptor, including zero bytes. As such, zero terminating the result would be kind of pointless. Instead, read() returns the amount of bytes that were successfully read. You must interpret that return value if you want to do correct reading.
You have to initialize the 'buf' with null. As 'buf' is declares local array and you didn't initialize it with null, 'read' call is reading up to sizeof(buf) which is 10 bytes. If you giving input string less than sizeof(buf) size, then it will read the remaining junk characters from the 'buf'. So initialize the 'buf' with null.
int main(int argc, char **argv) {
char buf[10] = {'\0'};
int ret;
while(1) {
ret = read(0, buf, sizeof buf);
printf("\n%s\n", buf);
}
return(0);
}
buf[10] = ... is undefined behavior. The buffer goes from 0..9, so the naive approach should be buf[9] = 0;.
This still doesn't work because it is not linked to how much you actually read. You do know this because of the ret variable - so add buf[ret] = 0; before trying to output buf.
edit: as pointed out in the comments, if the full amount of chars has been read (in this case 10) then buf[ret] is the same as buf[10] and so it is still undefined behavior. Easiest solution is to ensure the buffer is bigger than the max size you are trying to read.
you should set buf[ret] to '\0' not buf[10].
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
char buf[10];
int ret;
while(1) {
ret = read(0, buf, sizeof(buf));
buf[ret] = '\0';
printf("%s\n", buf);
}
return(0);
}
well, as commented there are some mistakes in my answer. I just want to point out the single point, so I haven't consider too much.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int main(int argc, char **argv) {
char buf[10];
int ret;
while(1) {
ret = read(0, buf, sizeof(buf) - 1); // keep last byte for termination charactor
if (ret == -1) {
printf("error:%s\n", strerror(errno));
break;
} else if (ret == 0) {
// end of file. such as ctrl + D
break;
} else {
// ret certainly less than sizeof(buf)
buf[ret] = '\0';
printf("%s\n", buf);
}
}
return(0);
}
I am simulating having two writers and one reader, based on this answer.
So, I create two pipes and I write one actual string to every pipe and one string which notifies the reader that he is done with this writer.
However, it will only read the first string and sometimes the ending string of the 2nd pipe.
What am I missing?
reader.c
int main() {
int w_no = 2;
int fd[w_no];
char * myfifo[w_no];
fill_names(myfifo, w_no);
print_names(myfifo, w_no);
struct pollfd fdtab[w_no];
int done[w_no];
/* create the FIFO (named pipe) */
int i;
for (i = 0; i < w_no; ++i) {
//fd[i] = open(myfifo[i], O_RDONLY);
while( (fd[i] = open(myfifo[i], O_RDONLY)) == -1);
fdtab[i].fd = fd[i];
fdtab[i].events = POLLIN;
fdtab[i].revents = 0;
done[i] = 0;
}
char buffer[1024];
ssize_t bytes;
printf("Edw prin\n");
while(not_all_done(done, w_no)) {
int retpoll = poll(fdtab, w_no, 300);
if(retpoll != 0) {
if (retpoll == -1) {
perror("poll");
break;
}
for(i = 0; i < w_no; ++i) {
if(fdtab[i].revents & POLLIN) {
printf("Edw %d %d %d %d\n", i, retpoll, fdtab[i].revents, POLLIN);
//read the written pipe
while((bytes = read(fdtab[i].fd, buffer, sizeof(buffer))) > 0)
printf("Read |%s| %d %d %d\n", buffer, retpoll, fdtab[i].revents, POLLIN);
if(!strcmp(buffer, "++"))
done[i] = 1;
}
}
} else if (retpoll == 0) {
/* the poll has timed out, nothing can be read or written */
printf("timeout from writer\n");
break;
}
}
for (i = 0; i < w_no; ++i) {
close(fd[i]);
}
free_names(myfifo, w_no);
return 0;
}
writer.c
int main() {
int w_no = 2;
int fd[w_no];
char * myfifo[w_no];
fill_names(myfifo, w_no);
print_names(myfifo, w_no);
/* create the FIFO (named pipe) */
int i;
int bytes;
for (i = 0; i < w_no; ++i) {
mkfifo(myfifo[i], 0666);
fd[i] = open(myfifo[i], O_WRONLY);
while( (bytes = write(fd[i], "Hi+", sizeof("Hi+"))) == 3);
printf("wrote %d bytes, %d\n", bytes, sizeof("Hi+"));
while( (bytes = write(fd[i], "++", sizeof("++"))) == 2);
printf("wrote %d bytes, %d\n", bytes, sizeof("++"));
}
for (i = 0; i < w_no; ++i) {
close(fd[i]);
unlink(myfifo[i]);
}
free_names(myfifo, w_no);
return 0;
}
Sample output:
/tmp/myfifo_0
/tmp/myfifo_0
/tmp/myfifo_1
/tmp/myfifo_1
wrote 4 bytes, 4
wrote 3 bytes, 3
wrote 4 bytes, 4
Edw prin
wrote 3 bytes, 3
Edw 0 2 17 1
Read |Hi+| 2 17 1
Edw 1 2 1 1
Read |Hi+| 2 1 1
^C
EDIT
When the Hi+ strings are arriving the value of bytes is 7.
The ending string I am trying to send is ++, but it doesn't get read.
EDIT_2
char* concat(char *s1, char *s2) {
char *result = malloc(strlen(s1) + strlen(s2) + 1); //+1 for the null-terminator
//in real code you would check for errors in malloc here
strcpy(result, s1);
strcat(result, s2);
return result;
}
void fill_names(char* f[], int n) {
int i = 0;
char * buf = "/tmp/myfifo_";
char str[15];
for (; i < n; ++i) {
sprintf(str, "%d", i);
f[i] = concat(buf, str);
}
}
Idea
Maybe the writer closes and unlinks the pipes before the data is read from them? If so, what should I do to prevent that?
If put a sleep(10) before that, it wont' change behaviour, it will just read the two first strings, but it will take more time and then it will hang up (because it waits the ending strings).
EDIT_3
I also have a main.c which execs reader and writer.
There is a problem in your string writing:
while( (bytes = write(fd[i], "Hi+", sizeof("Hi+"))) == 3);
printf("wrote %d bytes, %d\n", bytes, sizeof("Hi+"));
while( (bytes = write(fd[i], "++", sizeof("++"))) == 2);
printf("wrote %d bytes, %d\n", bytes, sizeof("++"));
Here you send 7 bytes: H i + \0 + + \0 , because the sizeof() of a string litteral includes the null terminator.
By the way, while((bytes=write(...))==3) will loop as long as 3 bytes could be written. This doesn't happen here because of the null terminator your writing as well. But better remove the enclosing while.
As the pipe is a stream, nothing garantees you will receive the bytes in two distinct reads. In fact, all your explanations and logs show that your receive all the 7 bytes at once.
However, you print the content using printf("Read |%s| %d %d %d\n"...): the result of prining a string that includes a '\0" is undefined. In your case, the printed string is truncated. So only "Hi+" is printed but "\0++" remains hidden in the buffer.
By the way, while((bytes = read(...)) > 0) could loop and print several times. This is not per se a problem. It's just that if the writer sends the data in time, the continuous reading could temporary lock out the reading of the other pipes. Generally in a poling programme, one prefer to read a little bit from every ready pipe.
Your check for the ending string
if(!strcmp(buffer, "++"))
done[i] = 1;
might in most cases not succeed. You are not sure that one write on one side will result in on read in the other side. So your "++" string will not necessarily be at the begin of the buffer. It could be anywhere in the buffer, so you have to search for it. It could even be split between two successive reads.
By the way, it might be that read() only finds back partial data (ex: "i+") without the terminating null. If you'd then try to print your buffer assuming that there is a valid string in it, you'd risk a buffer overflow.
Recommendation:
If your named pipes are meant for processing text data, I would suggest to add a '\n' at the end of each group of data you want to send, and write the strings to the pipe without the terminating null:
bytes = write(fd[i], "Hi+\n", sizeof("Hi+\n")-1);
Then, when you read, you could manage the buffer like a string: always add the trailing 0:
bytes = read(fdtab[i].fd, buffer, sizeof(buffer)-1); // leave a byte for terminator
if (bytes>0) {
buffer[bytes]=0; // end of string.
// process the string in the buffer
}
else if (bytes==0) {
done[i]=1;
}
Finally for identifying your end command, assuming that you've send it as "++\n" there are three possibilities:
if (strncmp(buffer,"++\n",3)==0 /* it's at the beginning of the buffer */
|| strstr(buffer, "\n++\n") ) /* it's in the middle but not a subpart and preceded by a packet separator */
done[i]=1;
But you also have to check for splits between two reads. This is more delicate, but I'm sure you find a way ;-)
Try to also print the number of bytes that you read in your reader program. My guess is that you have read some more bytes than you think, but when printing the string you only get the bytes before the first terminating zero.
Was it your intention to send terminating zeros on the named pipe? Maybe it would have been better to send something else like a newline?
Here i am trying to create a simple client and a server using pipes. I fork a process to make the child act as a client and parent as the server. Below is the code:
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
void errorMsg(char* msg)
{
printf("\n%s\n", msg);
// exit(0);
}
int main()
{
int servfd[2];
int clntfd[2];
int chldpid;
if(pipe(servfd) < 0)
errorMsg("Unable to create server pipe.!!");
if(pipe(clntfd) < 0)
errorMsg("Unable to create client pipe.!!!");
if((chldpid = fork()) == 0)
{
char* txt = (char*) calloc(256, sizeof(char));
close(servfd[1]);
close(clntfd[0]);
printf("#Client: Enter a string: ");
//scanf("%s", txt); //or fgets
printf("Entered.!!");
int n;
txt = "Anything that you want will not be considered no matter what you do!!";
char txt1[256];
write(clntfd[1], txt, 256);
//if(txt1[strlen(txt1) - 1] = '\n')
//{ printf("asdasdas");
//txt[strlen(txt) - 1] = '\0';}
//int i = 0;
//for(i = 0; i < 256; i++)
//printf("%c", txt1[i]);
while((n = read(servfd[0], txt1, 256)) > 0)
printf("\nAt client: %d bytes read\n\tString: %s\n", n, txt1);
}
else
{
//printf("Parent: \n\n");
close(servfd[0]);
close(clntfd[1]);
char* txt = NULL;
int n, n1;
n = read(clntfd[0], &txt, 256);
printf("Server read: %d", n);
n1 = write(servfd[1], &txt, 256);
printf("Server write: %d", n1);
wait(chldpid);
}
exit(0);
}
Question 1:
This is what is happening. When i run the program, it only prints Anything that yo (exactly 16 chars) and nothing else. When i tried to see the complete contents of txt1 using the for loop shown in comments, i found that there is null value (God knows from where) after yo in txt1. After it there are normal contents as they should be. Any idea why this is happening?
Edit:
The number of bytes read and written, when i try to print them at appropriate places, are all correct. It prints 256 bytes read. However, the size of txt1 by strlen comes out to be '16'. Also, the program hangs after printing part of the string.
Question 2:
When i try to get a string from user using scanf or fgets also shown in comments, the program terminates as soon as i press enter. No clue about that too as of why that could be happening.
Any insight on the behaviors would be helpful. Sorry for multiple questions. Thanks for your time.! I am using ubuntu 12.04, if that could be of any help.
I have added various comments and corrections to your code. it now works as intended.
Your main issue was as pointed out by codeaddict that you did not allocate buffers. I was surprized that you didn't crash with a SIGSEGV.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void errorMsg(char* msg)
{
printf("\n%s\n", msg);
// exit(0);
}
// move this into global space and make it const (non modifiable, easyer to debug)
const char text_to_send[] = "Anything that you want will not be considered no matter what you do!!";
int main()
{
int servfd[2];
int clntfd[2];
int chldpid;
if(pipe(servfd) < 0)
errorMsg("Unable to create server pipe.!!");
if(pipe(clntfd) < 0)
errorMsg("Unable to create client pipe.!!!");
if((chldpid = fork()) == 0)
{
char txt[256]; // You have to actually allocate a buffer (aka enough memory to hold your string. You have allocated a pointer to a buffer, but no actual buffer)
close(servfd[1]);
close(clntfd[0]);
printf("#Client: Enter a string: ");
scanf("%s", txt); // since you now actually have a buffer to put the input into this no longer fails
printf("Entered.!!\n");
int n;
char txt1[256];
write(clntfd[1], text_to_send, sizeof(text_to_send)); // write only as much as you actually have to say, not the whole size of your buffer
while((n = read(servfd[0], txt1, 256)) > 0)
printf("\nAt client: %d bytes read\n\tString: %s\n", n, txt1);
// this is not nessesary at this point, but it is good style to clean up after yourself
close(servfd[0]);
close(clntfd[1]);
}
else
{
//printf("Parent: \n\n");
close(servfd[0]);
close(clntfd[1]);
char txt[256]; // same here, you need to actually allocate a buffer.
int n, n1;
n = read(clntfd[0], txt, 256); // read into txt, not &txt. you want to read into your buffer pointed to by txt, not into the part of memory that contains the pointer
printf("Server read: %d\n", n);
n1 = write(servfd[1], txt, n); // do not send the whole buffer, just as much as you have actually useful information in it
printf("Server write: %d\n", n1);
// close the loose file descriptors, else your child will read on them forever
close(servfd[1]);
close(clntfd[0]);
int status;
wait(&status); // this is called like this. if you want to use the pid you call waitpid(chldpid, &status, 0);
}
exit(0);
}
In the parent process you are doing:
char* txt = NULL;
.....
n = read(clntfd[0], &txt, 256);
which is incorrect as you are reading data in the buffer pointed to by txt but you've not allocated the buffer!! What you are seeing is a manifestation of an undefined behavior.
I cannot for the life of me remember how to do this. This program opens a file then reads the file. All I would like it to do is print out the contents it has just read.
int main(int argc, char *argv[])
{
char memory[1000]; //declare memory buffer size
int fd = 0;
int count = 1000;
if ((fd = open(argv[1], O_RDONLY)) == -1)
{
fprintf(stderr, "Cannot open.\n");
exit(1);
}
read(fd, memory, count);
//printf the buffered memory contents
return 0;
}
printf accepts %s format to print a C-string. However, by default it requires that string to have a null-terminator (0x0 ASCII code). If you are sure it was read by the call to read then you can do this:
printf("%s\n", memory);
However, you cannot be sure. Because you don't even check how many bytes were read... or for error code.
So you have to fix your code first.
Once you are done checking for errors and know how many bytes were read, you can do this:
printf("%.*s\n", (int)bytes_that_were_read, memory);
Good luck!
for (unsigned int i = 0; i < count; i++) {
printf("%c", memory[i]);
}
Do you have to stick to printf() for some reason? What if the file is binary with '\0' somewhere inside? This will break even printf("%.*s", ...). If you read with read() you should be able to write with write():
while (bytes_written < bytes_read)
{
ssize_t x = write(STDOUT_FILENO,
memory + bytes_written,
bytes_read - bytes_written);
if (-1 == x)
{
exit(1);
}
bytes_written += x;
}
Set the last char to \0 in memory
use printf()
Or read one character less because last one you will need to set as \0
You can use a for loop and printf("%c", buffer[i]) to print one char at a time or you can use printf("%s", buffer) if the buffer is a null-terminated string.
I'd encountered bug (probably) that I can't explain and I would be happy if someone can.
**I wrote the following program:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <string.h>
int main(int argc, char** argv)
{
char arr1[5], arr2[5], arr3[5];
struct iovec iov[3];
ssize_t n;
int fd, i;
fd = open("/home/oz/Desktop/test", O_RDONLY);
if (fd == -1)
{
perror("open error");
return (1);
}
iov[0].iov_base = arr1;
iov[1].iov_base = arr2;
iov[2].iov_base = arr3;
iov[0].iov_len = 5;
iov[1].iov_len = 5;
iov[2].iov_len = 5;
n = readv(fd, iov, 3);
if (n == -1)
{
perror("read error");
return (1);
}
for (i = 0; i < 3; i++)
{
printf("Buffer %d Content : [%s]\n", i, (char *)iov[i].iov_base);
}
// DEBUG - START
printf("Total bytes read : %d\n", (int)n);
char * TEST = iov[0].iov_base;
printf("TEST LAST CHARACTER (int)= %d.\nTEST LENGTH = %d\n", TEST[5], (int)strlen(TEST));
// DEBUG - END
return 0;
}
The content of the file I read from (it's a one line text file):
123456789012345678901234567890
**The output
Buffer 0 Content : [12345]
Buffer 1 Content : [67890]
Buffer 2 Content : [12345]
Total bytes read : 15
TEST LAST CHARACTER (int)= 127.
TEST LENGTH = 6
**My Question:
Character with ASCII value of 127 was added to the first buffer from some unknown reason. (In my standard output I acctually see it as white square between '5' and ']' in the first line of the output.
Why does that strange thing occurred ?
Thank you..
No extra character is being added. You have two bugs in your program.
You reference TEST[5] (that is, arr1[5]) which is beyond the end of the arr1 array. C ararys are zero based, so the only valid values are: arr1[0], arr1[1], arr1[2], arr1[3], and arr1[4]. arr1[5] is the sixth entry in the array, not the fifth.
You print a character array that doesn't have a nul termination. C strings require a terminating zero, which you do not provide. As a consequence, the run-time system happily prints whatever characters are beyond the end of the array.
Make these changes to your program:
printf("Buffer %d Content : [%5.5s]\n", i, (char *)iov[i].iov_base);
...
printf("TEST LAST CHARACTER (int)= %d.\nTEST LENGTH = %d\n", TEST[4], 5);
Firstly, you're looking at TEST[5] which is the sixth character in a buffer of 5, in other words, it's totally random at this point.
Secondly, strlen(TEST) depends on TEST being terminated with a zero, something that readv()does not guarantee. The length of 6 is once again random since it depends on memory outside your buffers.