admin管理员组

文章数量:1431426

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
  • 3 In the reader you print from (i=0; i<BUFFSIZE; i++). You should instead do i < 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:46
  • 1 You don't check the result of write(). It is possible that less bytes were accepted/sent. – Wiimm Commented Nov 19, 2024 at 13:52
  • It is possible to guarantee the writer wrote in a single batch all? – user3318590 Commented Nov 19, 2024 at 13:58
  • See the PIPE_BUF section of man 7 pipe – Shawn Commented Nov 19, 2024 at 14:45
  • Modern POSIX systems usually limit the information in a pipe to 64 KiB (65536 bytes). Historically, the capacity of a pipe was often 5 KiB (5120 bytes); POSIX only requires 4 KiB (4096 bytes). Your reader code should only report on the number of bytes that were read (as diagnosed by @Verpous). Always pay attention to the number of bytes read, and don't try to manipulate bytes that were not read. The writer will wait until all the data that you request to be written has been written. However, if there is no reader, or the reader is slow, it will wait until there is space in the pipe again. – Jonathan Leffler Commented Nov 19, 2024 at 15:36
 |  Show 6 more comments

1 Answer 1

Reset to default 0

There'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.

本文标签: cPipe read maximum number of elementsStack Overflow