2

I have two programs, server and client. Server should read a file and then send its content through a named pipe to client. But my server reads only two chars from file, and then exits. What is wrong with this code?

server.c:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#define FIFO_NAME "american_maid"

int main(void)
{
    char line[300];
    int num, fd;
    FILE *fp;
    fp = fopen("out.txt","r");

    mknod(FIFO_NAME, S_IFIFO | 0666, 0);

    printf("waiting for readers...\n");
    fd = open(FIFO_NAME, O_WRONLY);
    printf("got a reader--type some stuff\n");

    while (fgets(line, sizeof(line), fp)) {
        if ((num = write(fd, line, strlen(line))) == -1)
            perror("write");
        else
            printf("speak: wrote %d bytes\n", num);
    }

    fclose(fp);

    return 0;
}

client.c:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#define FIFO_NAME "american_maid"

int main(void)
{
    char s[300];
    int num, fd;

    mknod(FIFO_NAME, S_IFIFO | 0666, 0);

    printf("waiting for writers...\n");
    fd = open(FIFO_NAME, O_RDONLY);
    printf("got a writer\n");

    do {
        if ((num = read(fd, s, 300)) == -1)
            perror("read");
        else {
            s[num] = '\0';
            printf("tick: read %d bytes: \"%s\"\n", num, s);
        }
    } while (num > 0);

    return 0;
}
yak
  • 3,770
  • 19
  • 60
  • 111
  • 1
    If it reads 300 bytes, client'll write a char past the end of buffer 's'. That isn't the problem you describe. – Lee Meador Apr 11 '13 at 19:33
  • Sorry my suggestion (not to create the file in the client code) didn't help. I've delete the answer so you get more attention. – luser droog Apr 11 '13 at 19:43
  • Is the 'current' folder the same for both programs? There is no path on the FIFO filename (e.g. `/tmp/american_maid`) – Lee Meador Apr 11 '13 at 19:46
  • nope, they're in the same dir (client, server and american_maid fifo) – yak Apr 11 '13 at 19:49
  • Use the ferror() and feof() functions to distinguish between an error condition and an end-of-file condition when fgets() returns NULL and see if there is an interesting error code. – Lee Meador Apr 11 '13 at 20:01
  • 1
    Check that your `open()` calls worked. Note that if you read 300 bytes in the client, writing to `s[num]` writes beyond the end of your array; it might mess up the number of bytes of data that's read. – Jonathan Leffler Apr 11 '13 at 20:16
  • @Jonathan Leffler: checed open - open worked. So what do you suggest about writing to s[num] how can I do this? I still cant get this working properly :/ – yak Apr 12 '13 at 10:39

2 Answers2

1

When I run the code shown below using the command sequence:

$ ln -s server.c out.txt
$ ./client &
$ ./server
$

I get a copy of the source code printed by the client program. Similarly when I run the commands using:

$ ./server &
$ ./client
$

The revised code is not modified all that significantly. It avoids do { } while(...) loops — they're so seldom really beneficial — and is very careful about not overflowing buffers. The code also has superfluous headers removed.

server.c

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define FIFO_NAME "american_maid"

int main(void)
{
    const char infile[] = "out.txt";
    FILE *fp = fopen(infile, "r");

    if (fp == 0)
    {
        fprintf(stderr, "Failed to open %s for reading", infile);
        return(1);
    }

    mknod(FIFO_NAME, S_IFIFO | 0666, 0);

    printf("waiting for readers...\n");
    int fd = open(FIFO_NAME, O_WRONLY);
    if (fd > 0)
    {
        char line[300];
        printf("got a reader--type some stuff\n");

        while (fgets(line, sizeof(line), fp))
        {
            int len = strlen(line);
            int num = write(fd, line, len);
            if (num != len)
                perror("write");
            else
                printf("speak: wrote %d bytes\n", num);
        }
        close(fd);
    }

    fclose(fp);

    return 0;
}

client.c

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>

#define FIFO_NAME "american_maid"

int main(void)
{
    const char outfile[] = "client.out";
    FILE *fp = fopen(outfile, "w");

    if (fp == 0)
    {
        fprintf(stderr, "Failed to open %s for writing\n", outfile);
        return 1;
    }

    printf("waiting for writers...\n");
    mknod(FIFO_NAME, S_IFIFO | 0666, 0);

    int fd = open(FIFO_NAME, O_RDONLY);
    if (fd > 0)
    {
        int num;
        char s[300];
        printf("got a writer\n");

        while ((num = read(fd, s, sizeof(s))) > 0)
        {
            printf("tick: read %d bytes: \"%.*s\"\n", num, num, s);
            fprintf(fp, "%.*s", num, s);
        }

        close(fd);
    }
    fclose(fp);

    return 0;
}

Note that this version writes its output to file client.out; even when given a file with some very long lines to process (2049 bytes including the newline at the end), the output in client.out exactly matches the input in out.txt.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
0

Remove the line mknod(FIFO_NAME, S_IFIFO | 0666, 0); from the file client.c. Then the program will work as expected. Server will create a file and sent the content of the file to fifo.

Agustin Meriles
  • 4,866
  • 3
  • 29
  • 44
Rish
  • 804
  • 8
  • 15
  • did it already, didnt help (the problem is the same after I commented this line in client code) – yak Apr 11 '13 at 19:52
  • Actually, having both programs try to create exactly the same file isn't a bad thing, it means either can start first -- and ignoring the mknod return means he can just make a regular file there. It's not usual, but it's not bad, either, in this case. – jthill Apr 11 '13 at 20:40