Basic example Namedpipe server and client
In this program, you are going to learn
How to open namedpipes for reading and writing ?
How to read data ?
How to write data ?
Topics in this section,
Topics in this section,
Let us answer few basic questions in this namedpipe
What is the purpose of mkfifo
in the code?
See Answer
mkfifo
is used to create a named pipe with a specific path and permission mode.
Why is O_RDONLY
used when opening server_fifo for the first time?
See Answer
O_RDONLY
indicates that the server is opening the named pipe for reading, expecting input from a client.
What happens if the server tries to open a non-existent named pipe using O_RDONLY
?
See Answer
If the named pipe doesn’t exist, the open
call will block until another process creates it.
This is common in inter-process communication.
Why is O_WRONLY
used when reopening server_fifo for writing?
See Answer
After receiving data from the client, the server reopens the named pipe for writing (O_WRONLY) to send a response back.
What is the significance of using O_WRONLY
for the second open
call?
See Answer
It designates the server’s intention to write to the named pipe, indicating a shift from reading to writing mode.
How does the server handle errors when opening the named pipe for reading or writing?
See Answer
The code checks the return value of the open
call and prints an error message using perror
if the operation fails.
How does the server handle cases where the named pipe is never opened for writing by the client?
See Answer
The server would block indefinitely at the write
operation until the client opens the named pipe for reading.
What is the significance of using unlink(FIFO_PATH)
in the signal handler?
See Answer
It removes the named pipe from the file system, ensuring that resources are properly cleaned up when the server exits.
Why are there multiple calls to close(server_fifo)
in the code?
See Answer
File descriptors need to be closed after usage to release system resources. Multiple calls ensure all relevant file descriptors are closed.
There are many functions used in namedpipe. We can classify those functions based on functionalities.
mkfifo
open
read
write
close
mkfifo
is used to create a named pipe at a specified path (FIFO_PATH) with a given permission mode. For example,
mkfifo(FIFO_PATH, 0666);
open
is used to opening the named pipe with a given permission mode. For example,
server_fifo = open(FIFO_PATH, O_RDONLY);
server_fifo = open(FIFO_PATH, O_WRONLY);
read
is used to read data from the named pipe, expecting input from a client. For example,
ret = read(server_fifo, buffer, sizeof(buffer) - 1);
write
is used to write a data to the named pipe, writing input to the client. For example,
ret = write(server_fifo, buffer, strlen(buffer));
close
is used to close the namepipe To free up system resources associated with the namedpipe. For example,
(void)close(server_fifo);
See the full program below,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#define FIFO_PATH "/tmp/my_named_pipe"
#define BUFFER_SIZE 1024
int main(void)
{
int ret;
int server_fifo;
char buffer[BUFFER_SIZE];
mkfifo(FIFO_PATH, 0666);
server_fifo = open(FIFO_PATH,
O_RDONLY);
if (server_fifo == -1) {
perror("open server FIFO");
return -1;
}
printf("Server is ready\n");
ret = read(server_fifo,
buffer, sizeof(buffer) - 1);
if (ret < 0) {
(void)close(server_fifo);
unlink(FIFO_PATH);
printf("Server is shutting down.\n");
return -2;
} else {
buffer[ret] = '\0';
printf("Received : %s\n",
buffer);
(void)close(server_fifo);
}
snprintf(buffer,
sizeof(buffer), "Hello from server!\n");
server_fifo = open(FIFO_PATH,
O_WRONLY);
if (server_fifo != -1) {
ret = write(server_fifo,
buffer, strlen(buffer));
if (ret == -1) {
perror("write error");
(void)close(server_fifo);
return -3;
}
printf("sent = %s\n", buffer);
}
(void)close(server_fifo);
return 0;
}
1$ gcc -o server server.c
2
3$ sudo ./server
4
5Server is ready
6Received : Hello from client!
7
8sent = Hello from server!
There are many functions used in namedpipe. We can classify those functions based on functionalities.
open
write
read
close
open
is used to opening the named pipe with a given permission mode. For example,
client_fifo = open(FIFO_PATH, O_WRONLY);
client_fifo = open(FIFO_PATH, O_RDONLY);
write
is used to write a data to the named pipe, writing input to the client. For example,
ret = write(client_fifo, buffer, sizeof(buffer) - 1);
read
is used to read data from the named pipe, expecting input from a client. For example,
ret = read(client_fifo, buffer, sizeof(buffer) - 1);
close
is used to close the namepipe To free up system resources associated with the namedpipe. For example,
(void)close(client_fifo);
See the full program below,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#define FIFO_PATH "/tmp/my_named_pipe"
#define BUFFER_SIZE 1024
int main(void)
{
int ret;
int client_fifo;
char buffer[BUFFER_SIZE];
client_fifo = open(FIFO_PATH,
O_WRONLY);
if (client_fifo == -1) {
perror("open client FIFO");
return -1;
}
printf("Client is ready\n");
snprintf(buffer,
sizeof(buffer), "Hello from client!\n");
ret = write(client_fifo,
buffer, sizeof(buffer) - 1);
if (ret < 0) {
printf("Client is shutting down.\n");
(void)close(client_fifo);
return -2;
} else {
buffer[ret] = '\0';
printf("sent = %s\n", buffer);
(void)close(client_fifo);
}
client_fifo = open(FIFO_PATH,
O_RDONLY);
if (client_fifo == -1) {
perror("open FIFO error");
return -4;
}
memset(buffer, 0,
sizeof(buffer));
ret = read(client_fifo,
buffer, sizeof(buffer) - 1);
if (ret < 0) {
(void)close(client_fifo);
printf("Client is shutting down.\n");
return -5;
} else {
buffer[ret] = '\0';
printf("Received: %s",
buffer);
}
(void)close(client_fifo);
return 0;
}
1$ gcc -o client client.c
2
3$ sudo ./client
4
5Client is ready
6sent = Hello from client!
7
8Received: Hello from server!
There are many functions used in namedpipe. We can classify those functions based on functionalities.
mkfifo
open
read
write
close
mkfifo
is used to create a named pipe at a specified path (FIFO_PATH) with a given permission mode. For example,
mkfifo(FIFO_PATH, 0666);
open
is used to opening the named pipe with a given permission mode. For example,
server_fifo = open(FIFO_PATH, O_RDONLY);
server_fifo = open(FIFO_PATH, O_WRONLY);
read
is used to read data from the named pipe, expecting input from a client. For example,
ret = read(server_fifo, buffer, sizeof(buffer) - 1);
write
is used to write a data to the named pipe, writing input to the client. For example,
ret = write(server_fifo, buffer, strlen(buffer));
close
is used to close the namepipe To free up system resources associated with the namedpipe. For example,
(void)close(server_fifo);
See the full program below,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#define FIFO_PATH "/tmp/my_named_pipe"
#define BUFFER_SIZE 1024
#define NUM_MESSAGES 10
int main(void)
{
int ret, i;
int server_fifo;
char buffer[BUFFER_SIZE];
mkfifo(FIFO_PATH, 0666);
i = 0;
while (i < NUM_MESSAGES) {
server_fifo = open(FIFO_PATH,
O_RDONLY);
if (server_fifo == -1) {
perror("open server FIFO");
break;
}
printf("Server %d is ready\n",
i);
ret = read(server_fifo,
buffer, sizeof(buffer) - 1);
if (ret < 0) {
perror("read error");
break;
} else {
buffer[ret] = '\0';
printf("Received : %s\n",
buffer);
(void)close(server_fifo);
}
snprintf(buffer,
sizeof(buffer), "Hello from server!");
server_fifo = open(FIFO_PATH,
O_WRONLY);
if (server_fifo != -1) {
ret = write(server_fifo,
buffer, strlen(buffer));
if (ret == -1) {
perror("write error");
break;
}
printf("sent = %s\n", buffer);
}
(void)close(server_fifo);
++i;
}
(void)close(server_fifo);
return 0;
}
1$ gcc -o server server.c
2
3$ sudo ./server
4
5Server 0 is ready
6Received : Hello from client!
7sent = Hello from server!
8Server 1 is ready
9Received : Hello from client!
10sent = Hello from server!
11Server 2 is ready
12Received : Hello from client!
13sent = Hello from server!
14Server 3 is ready
15Received : Hello from client!
16sent = Hello from server!
17Server 4 is ready
18Received : Hello from client!
19sent = Hello from server!
20Server 5 is ready
21Received : Hello from client!
22sent = Hello from server!
23Server 6 is ready
24Received : Hello from client!
25sent = Hello from server!
26Server 7 is ready
27Received : Hello from client!
28sent = Hello from server!
29Server 8 is ready
30Received : Hello from client!
31sent = Hello from server!
32Server 9 is ready
33Received : Hello from client!
34sent = Hello from server!
There are many functions used in namedpipe. We can classify those functions based on functionalities.
open
write
read
close
open
is used to opening the named pipe with a given permission mode. For example,
client_fifo = open(FIFO_PATH, O_WRONLY);
client_fifo = open(FIFO_PATH, O_RDONLY);
write
is used to write a data to the named pipe, writing input to the client. For example,
ret = write(client_fifo, buffer, sizeof(buffer) - 1);
read
is used to read data from the named pipe, expecting input from a client. For example,
ret = read(client_fifo, buffer, sizeof(buffer) - 1);
close
is used to close the namepipe To free up system resources associated with the namedpipe. For example,
(void)close(client_fifo);
See the full program below,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#define FIFO_PATH "/tmp/my_named_pipe"
#define BUFFER_SIZE 1024
#define NUM_MESSAGES 10
int main(void)
{
int ret, i;
int client_fifo;
char buffer[BUFFER_SIZE];
i = 0;
while (i < NUM_MESSAGES) {
client_fifo = open(FIFO_PATH,
O_WRONLY);
if (client_fifo == -1) {
perror("open client FIFO");
break;
}
printf("Client %d is ready\n",
i);
snprintf(buffer,
sizeof(buffer), "Hello from client!");
ret = write(client_fifo,
buffer, sizeof(buffer) - 1);
if (ret < 0) {
perror("write error");
break;
} else {
buffer[ret] = '\0';
printf("sent = %s\n", buffer);
(void)close(client_fifo);
}
client_fifo = open(FIFO_PATH,
O_RDONLY);
if (client_fifo == -1) {
perror("open FIFO error");
break;
}
memset(buffer, 0,
sizeof(buffer));
ret = read(client_fifo,
buffer, sizeof(buffer) - 1);
if (ret < 0) {
perror("read error");
break;
} else {
buffer[ret] = '\0';
printf("Received: %s\n",
buffer);
}
++i;
}
(void)close(client_fifo);
return 0;
}
1$ gcc -o client client.c
2
3$ sudo ./client
4
5Client 0 is ready
6sent = Hello from client!
7Received: Hello from server!
8Client 1 is ready
9sent = Hello from client!
10Received: Hello from server!
11Client 2 is ready
12sent = Hello from client!
13Received: Hello from server!
14Client 3 is ready
15sent = Hello from client!
16Received: Hello from server!
17Client 4 is ready
18sent = Hello from client!
19Received: Hello from server!
20Client 5 is ready
21sent = Hello from client!
22Received: Hello from server!
23Client 6 is ready
24sent = Hello from client!
25Received: Hello from server!
26Client 7 is ready
27sent = Hello from client!
28Received: Hello from server!
29Client 8 is ready
30sent = Hello from client!
31Received: Hello from server!
32Client 9 is ready
33sent = Hello from client!
34Received: Hello from server!
Socket API |
Learning |
---|---|
mkfifo |
create a named pipe at a specified path (FIFO_PATH) with a given permission mode. |
open |
opening the named pipe with a given permission mode. |
read |
read data from the named pipe, expecting input from a client. |
write |
write a data to the named pipe, writing input to the client. |
Previous topic
Current topic
Other IPCs