4

I have to implement a "printing server". I have 1 client file, and 1 server file:

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

int get_line( char *dest, int size );

#define MAX 1024

void main ()
{
    char const *pipe = "printservers";
    char buffer[MAX];
    int fd;

    get_line( buffer, MAX );

    if( mkfifo( pipe, 0666 ) < 0 )
    {
        printf( "Cannot create a pipe\n" );
        exit( EXIT_FAILURE );
    }

    fd = open( pipe, O_WRONLY );

    write( fd, buffer, MAX );

    close( fd );

    //unlink( pipe );

}

int get_line( char *dest, int size )
{
    int c, i;
    for( i = 0; i < size - 1 && ( c = getchar() ) != EOF && c != '\n'; ++i )
        dest[i] = c;
    if( c == '\n' )
    {
        dest[i] = c;
        ++i;
    }
    dest[i] = '\0';
    return i;
}

This is the client, which reads from the standard input a line and writes into a named pipe called printservers. This works as intended.

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

#define MAX_BUF 1024
#define MAX_PID 8

int main()
{
    int fd;
    char * myfifo = "printservers";
    char buf[MAX_BUF];

    /* open, read, and display the message from the FIFO */
    fd = open( myfifo, O_RDONLY );
    while( 1 )
    {
        if( read( fd, buf, MAX_BUF ) > 0 )
            printf("Received: %s\n", buf);
    }
    close(fd);

    return 0;
}

This is the server, which are read from the pipe. But it does not work with the while loop. If i send a message from the client, the first message is printed, but the following messages are ignored. Could somebody help me with my problem? Thanks Patrik

Newton Falls
  • 2,148
  • 3
  • 17
  • 22
Zagatho
  • 523
  • 1
  • 6
  • 22
  • 1
    Are you invoking the client process for each submission? If so, you should create the fifo in the server so it is the same entity each time. – Amardeep AC9MF May 06 '14 at 15:52
  • 2
    Your server should work as expected - try running it alone and `echo` something to the fifo on another terminal. However, you should end `buf` with a `\0` character before using `printf` – user12205 May 06 '14 at 15:54
  • @Amardeep Does it make any difference? Because i tried it and it works in both ways. – Zagatho May 06 '14 at 16:04
  • You've omitted something important. With the code as shown, every client after the first will experience a mkfifo() EEXIST failure and bail out with `"Cannot create a pipe"`. I suspect you were actually unlink()ing the FIFO at the end of every client run (as your commented code suggests): you ran the client afresh, which blocked on open() until you ran the server, then that first client unlinked the FIFO, leaving the poor server perpetually stuck in a tight and silent read()/EOF loop against an unlinked FIFO with no hope of future input. – pilcrow May 07 '14 at 03:08

1 Answers1

2

There is a coding error in the server's while loop - the server will never exit the loop even when there is an error or the server receives eof on the FIFO. It should be changed to something like this:

while(1)
{
    if((bytesread = read( fd, buf, MAX_BUF - 1)) > 0)
    {
        buf[bytesread] = '\0';
        printf("Received: %s\n", buf);
    }
    else
        break;
}

Your other problem is that your client sends a single line and then closes the FIFO. The server reads until EOF. So it is going to read the single line, then hit EOF because the client closed. This is completely normal.

Where it becomes a problem is when you want your server to provide service to multiple clients. In that case you don't want to quit reading after every individual client closes its end. The semantics are such that the server will only see EOF after the last of all clients close. So an easy way to accommodate the server handling multiple clients is to open your server-side FIFO as read/write. Then there will always be a "writer", the server itself, with write end of the FIFO open. This will prevent the server from seeing EOF until you decide to shut it down.

A second problem is that you need to read and write in loops. You are not guaranteed to get your full data request filled in one call.

Also, having the client create the FIFO that the server reads is an odd approach. Normally you want the server to create a known FIFO to which clients connect.

Duck
  • 26,924
  • 5
  • 64
  • 92
  • Thanks Duck for your answer. If i use "write( 1, buf, size ), where size is the return value of read, only 1 character apears on the other terminal. If i use "write( 1, buf, BUFMAXSIZE ), it writes the message plus garbage ( some hiroglyphes ). Can you explain whats wrong? – Zagatho May 06 '14 at 16:38
  • Not really without see what you are doing. I would suggest you write `strlen` bytes in the client not MAX bytes which going to write the string and whatever garbage in buf that follows it. – Duck May 06 '14 at 17:12
  • Hmm, this isn't actually his problem (his non-problem)? The code posted doesn't terminate on EOF — it stays in a tight read() loop. As I comment above, I don't think we're seeing the actual and complete code. – pilcrow May 07 '14 at 13:29
  • @pilcrow, you're right. I missed the while(1). I was focused on OP sending one msg per client. I'll amend the answer when I get a chance. – Duck May 07 '14 at 13:52