I tried to write a simple reader and writer program.
reader:
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFSIZE 65600 //921600 // 640*480*3
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
int main()
{
int fd;
ssize_t n;
char buf[BUFFSIZE];
long int i;
if ( (fd = open("./shared/test", O_RDONLY)) < 0)
err("open")
while( (n = read(fd, buf, BUFFSIZE) ) > 0) {
printf("Read (%d): ", n);
for (i=0; i<BUFFSIZE; i++)
printf("%c", buf[i]);
printf("\n");
}
close(fd);
return 0;
}
writer:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFFSIZE 65600 //921600 // 640*480*3
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
int main()
{
int fd;
char buf[BUFFSIZE];
long int i, j;
mkfifo("./shared/test", 0666);
if ( (fd = open("./shared/test", O_WRONLY)) < 0)
err("open")
// main loop
j=0;
while (1){
for (i=0;i<BUFFSIZE;i++){
buf[i]= j + '0';
}
j++;
buf[BUFFSIZE-1]=j + '0';
write(fd, buf, sizeof(buf));
sleep(10);
}
close(fd);
return 0;
}
The program correctly works up to BUFFSIZE 65535 (2^16-1). When I tried with bigger number it gives me for example: Read (65536): 0000000000000000000000000000000000000 and after junk elements
How can I use it for bigger number of elements? Thanks, Joe
I tried to write a simple reader and writer program.
reader:
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFSIZE 65600 //921600 // 640*480*3
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
int main()
{
int fd;
ssize_t n;
char buf[BUFFSIZE];
long int i;
if ( (fd = open("./shared/test", O_RDONLY)) < 0)
err("open")
while( (n = read(fd, buf, BUFFSIZE) ) > 0) {
printf("Read (%d): ", n);
for (i=0; i<BUFFSIZE; i++)
printf("%c", buf[i]);
printf("\n");
}
close(fd);
return 0;
}
writer:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFFSIZE 65600 //921600 // 640*480*3
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
int main()
{
int fd;
char buf[BUFFSIZE];
long int i, j;
mkfifo("./shared/test", 0666);
if ( (fd = open("./shared/test", O_WRONLY)) < 0)
err("open")
// main loop
j=0;
while (1){
for (i=0;i<BUFFSIZE;i++){
buf[i]= j + '0';
}
j++;
buf[BUFFSIZE-1]=j + '0';
write(fd, buf, sizeof(buf));
sleep(10);
}
close(fd);
return 0;
}
The program correctly works up to BUFFSIZE 65535 (2^16-1). When I tried with bigger number it gives me for example: Read (65536): 0000000000000000000000000000000000000 and after junk elements
How can I use it for bigger number of elements? Thanks, Joe
Share Improve this question asked Nov 19, 2024 at 13:28 user3318590user3318590 912 silver badges15 bronze badges 11 | Show 6 more comments1 Answer
Reset to default 0There's no need for both programs to have the same buffer size, if you do proper checking of your buffer. That's the idea of the pipe. Checking the read() and write() calls for incomplete writes or reads is important, and to consider that if a read doesn't read a complete buffer, the rest of it will have no interesting data to be printed. Check this copy of your code (corrected in places you make mistakes) and see how things go.
Normally, a reading process will be blocked until all its buffer is filled with data, but if no more data is available (because all writer processes have closed their writing side) the process will be unblocked, received all the buffer data, until there's no more data in the buffer stream, and EOF will be signalled then (read() returns 0 characters without blocking on EOF)
Normally, a writing process will be blocked if its buffer is larger than the pipe internal available buffer, and the write() system call will block, waiting for more space to be available, until all its buffer has been written. This event will release the writer from the write() system call and return to the process.
This system makes the reader and the writer processes never sense the internal buffering in the pipe. Indeed the data could be copied directly from the writer to the reader, but this would block both processes in a rendez vous, sleeping the reader until a writer starts writing data, and releasing only the process that has finished copying its data to the other side, which is not desirable, so a buffer has been implemented to allow avoiding the rendez-vous for readers and writers.
reader.c
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFSIZE 65600 //921600 // 640*480*3
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
int main()
{
int fd;
ssize_t n;
char buf[BUFFSIZE];
long int i;
mkfifo("test", 0666);
if ( (fd = open("test", O_RDONLY)) < 0)
err("open")
while( (n = read(fd, buf, BUFFSIZE) ) > 0) {
printf("Read (%zd): ", n);
/* you cannot warrant that
* BUFFSIZE chars have been read, so use
* n, instead of BUFFSIZE */
for (i = 0; i < n && i < 32; i++)
printf("%c", buf[i]);
if (i >= 32) printf(" ...\n");
printf("\n");
}
if (n < 0) {
err(strerror(errno));
}
close(fd);
return 0;
}
writer.c
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFFSIZE 921600 // 640*480*3
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
int main()
{
int fd;
char buf[BUFFSIZE];
long int i, j;
mkfifo("test", 0666);
if ( (fd = open("test", O_WRONLY)) < 0)
err("open")
/* you only need to do this once, as you never
* change the buffer contents. */
char *p = buf;
for (i = 1; i <= BUFFSIZE; i++, p++) {
/* this will write the pattern ....,....;....,....;
* in the buffer. */
switch(i % 10) {
case 5: *p = ','; break;
case 0: *p = ';'; break;
default: *p = '.'; break;
}
}
/* hmmmm.... j + '0'??? sure? I think you need
* this, instead: */
// buf[BUFFSIZE-1]='\0'; // '0' is not the same as '\0'
/* but you don't need it, as you tell write() where to
* stop writing */
// main loop
for (j = 0;; j++) {
/* as you defined buf of BUFFSIZE chars, sizeof buf will be
* that number, if you specify sizof(buf) you will write the
* last \0 char, and you don't want that to occur... or yes? */
printf("#%ld:\n", j);
ssize_t n;
char *p = buf;
size_t to_go = sizeof buf;
while ((n = write(fd, p, to_go)) > 0) {
p += n; /* advance the pointer n positions */
to_go -= n; /* reduce the chars to go in n */
}
if (n < 0) {
/* we got out of the loop because n < 0, this is because
* an error happened to write() */
err(strerror(errno));
}
sleep(10);
}
close(fd);
return 0;
}
Introduce also a delay in the reader (with a different time) and you will see how the slowest process slows the fastest, but no data is lost.
(i=0; i<BUFFSIZE; i++)
. You should instead doi < n
. There is no guarantee the OS will feed you the entire amount the writer wrote in a single batch. – Verpous Commented Nov 19, 2024 at 13:46write()
. It is possible that less bytes were accepted/sent. – Wiimm Commented Nov 19, 2024 at 13:52PIPE_BUF
section ofman 7 pipe
– Shawn Commented Nov 19, 2024 at 14:45