have to write two programs (a client and a server) which will do
chatting with each other using FIFOs (to pass message from one process to another). The
server process creates a SERVER_FIFO to receive client connections only. The server
maintains the list of online clients. Each client creates its own CLIENT_FIFO to receive
commands from server to be executed at client using system() system call. You can use
getpid() system call to retrieve client’s process id to be concatenated in the
CLIENT_FIFO name.
I only to create 2 fifo that communicate with each other
SERVER
// C program to implement one side of FIFO
// This side writes first, then reads
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int fd;
char * myfifo = "/tmp/myfifo";
mkfifo(myfifo, 0666);
char arr1[80], arr2[80];
while (1)
{
fd = open(myfifo, O_WRONLY);
fgets(arr2, 80, stdin);
write(fd, arr2, strlen(arr2)+1);
close(fd);
// Open FIFO for Read only
fd = open(myfifo, O_RDONLY);
// Read from FIFO
read(fd, arr1, sizeof(arr1));
// Print the read message
printf("User2: %s\n", arr1);
close(fd);
}
return 0;
}
==================================================================
CLIENT
// C program to implement one side of FIFO
// This side reads first, then reads
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int fd1;
// FIFO file path
char * myfifo = "/tmp/myfifo";
mkfifo(myfifo, 0666);
char str1[80], str2[80];
while (1)
{
// First open in read only and read
fd1 = open(myfifo,O_RDONLY);
read(fd1, str1, 80);
// Print the read string and close
printf("User1: %s\n", str1);
close(fd1);
fd1 = open(myfifo,O_WRONLY);
fgets(str2, 80, stdin);
write(fd1, str2, strlen(str2)+1);
close(fd1);
}
return 0;
}
Related
I am asked to do two chat programs so that user1 & user2 can send and receive the messages. The program should ask the user if he needs to continue chatting or no after every message is sent,
and If no, a goodbye message should be printed on the standard
output to inform the other user that chatting is terminated. Also, each user is allowed to send only up to 5 messages.
I created the next codes for the user1 and user2
the code of user 1:
"""
//Chat 1
// This side writes first, then reads
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int fd, count=0,sendAgain=0;
char * myfifo = "/tmp/myfifo";// Declare the FIFO file pathname
// Creating the named file(FIFO)
mkfifo(myfifo, 0666); // mkfifo(<pathname>, <permission>)
char Arr1[80], Arr2[80];
while (1)
{
// ***Open FIFO for write only****
fd = open(myfifo, O_WRONLY);
while (count!=5){
count++ ;
printf("\nYour message: ");
fgets(Arr1, 80, stdin);// Take an input Arr1 from user with maximum 100 length
write(fd, Arr1, strlen(Arr1)+1);// Write the input Arr1 on FIFO
printf("Do you want to continue?[1 or 2]\n1-Yes\n2-No\nAnswer: ");
scanf("%d",&sendAgain);
getchar();
if (sendAgain==2) {
break;
}
}
write(fd, "bye", strlen("bye")+1);
close(fd);// close the FIFO
// ***Open FIFO for read only****
fd = open(myfifo, O_RDONLY);
read(fd, Arr2, sizeof(Arr2));// Read from FIFO
printf("User2: %s\n", Arr2);// Print the message that was read
close(fd);// close the FIFO
}
return 0;
}
"""
and the code of the user 2
"""
//Chat 2
// This side reads first, then writes
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int fd1, count=0,YN=0;
char * myfifo = "/tmp/myfifo";// Declare the FIFO file pathname
// Creating the named file(FIFO)
mkfifo(myfifo, 0666); // mkfifo(<pathname>, <permission>)
char str1[80], str2[80];
while (1)
{
// ***Open FIFO for read only****
fd1 = open(myfifo,O_RDONLY);
read(fd1, str1, 80);
printf("User1: %s\n", str1);// Print the message that was read
close(fd1);
// ***Open FIFO for read only****
fd1 = open(myfifo, O_WRONLY);
while (count!=5){
count++ ;
printf("\nYour message: ");
fgets(str2, 80, stdin);// Take an input WriteArr from user with maximum 100 length
write(fd1, str2, strlen(str2)+1);// Write the input WriteArr on FIFO
printf("Do you want to continue?[enter 1 or 2]\n1-Yes\n2-No\nAnswer: ");
scanf("%d",&sendAgain);
getchar();
if (sendAgain==2) {
break;
}
}
write(fd1, "bye", strlen("bye")+1);
close(fd1);// close the FIFO
}
return 0;
}
"""
However, I faced a problem after I wrote a message and was asked if I wanted to continue, it allows me to write a message again if I said yes but without reading it from the other user and the program is stopping at this point. Also, if I chose "No" it ends the program without printing "bye" or even waiting for the other's user turn to write!
Output1 if yes entered
Output2
What kind of a way is correct for solving this problem?
For example I have a program named write.c that has 4 child processes and the child processes are write their PIDs to a single global named pipe.
Another program named read.cshould read this PIDs.
I have an approach like in below, but that approach has some problems.It can not read all PIDs, sometimes 3 of them and sometimes 2 of them.I think there is a synchronization problem , how can I solve this problem? :
writer.c:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(){
int fd;
char * myfifo = "/tmp/myfifo"; //FIFO file
char buffer[50];
mkfifo(myfifo, 0666); //creating the FIFO
for(int i=0;i<4;i++){ //creating 4 child process
if(fork() == 0) {
fd = open(myfifo, O_WRONLY); //each child process opens the FIFO for writing their own PID.
sprintf(buffer, "%d", getpid()); //each child process gets pid and assign it to buffer
printf("write:%s\n", buffer); // each child process prints to see the buffer clearly
write(fd, buffer, strlen(buffer)+1); //each child process writes the buffer to the FIFO
close(fd);
exit(0);
}
}
for(int i=0;i<4;i++) { //waiting the termination of all 4 child processes.
wait(NULL);
}
//parent area
}
reader.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
int main(int argc, char **argv) {
int fd1;
// FIFO file path
char * myfifo = "/tmp/myfifo";
// Creating the named file(FIFO)
mkfifo(myfifo, 0666);
char str1[80]; //str2[80];
while (1)
{
// First open in read only and read
fd1 = open(myfifo,O_RDONLY);
read(fd1, str1, 80);
// Print the read string and close
printf("read: %s\n", str1);
close(fd1);
}
}
This line writes the null byte into the fifo:
write(fd, buffer, strlen(buffer)+1);
as a result if you have two pids in the pipe you'll read the following string:
1234\02345\0
And the printf will print only till the first \0:
1234
To fix it, it's easier to transfer the PID as binary rather than formatting and parsing text:
Writer:
if(fork() == 0) {
fd = open(myfifo, O_WRONLY);
pid_t pid = getpid();
write(fd, &pid, sizeof(pid));
close(fd);
exit(0);
}
The reader:
fd1 = open(myfifo,O_RDONLY);
pid_t pid;
while (1) // whatever is your termination condition
{
read(fd1, &pid, sizeof(pid));
printf("read: %d\n", pid);
}
close(fd1);
i have fifo open in one side for read and in the other side for write, the read side close the fd he opened . is there a way of know if the reader closed this fd in the writer side ?
i want that the writer will have any notification about whether the reader is ready to read because if not my writer will get blocked on write .
writer.c :
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
int main()
{
int fd;
char * myfifo = "/tmp/fifo_pipe";
/* create the FIFO (named pipe) */
mkfifo(myfifo, 0666);
/* write "Hi" to the FIFO */
fd = open(myfifo, O_WRONLY);
write(fd, "Hey", sizeof("Hey"));
/*here is there a posibilty of know that the read side hase close hi's side of the pipe before write? */
write(fd, "test\n", strlen("test\n"));
close(fd);
/* remove the FIFO */
unlink(myfifo);
return 0;
}
reader.c :
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#define MAX_BUF 1024
int main()
{
int fd;
char * myfifo = "/tmp/fifo_pipe";
char buf[MAX_BUF];
/* open, read, and display the message from the FIFO */
fd = open(myfifo, O_RDONLY);
read(fd, buf, MAX_BUF);
printf("Received: %s\n", buf);
close(fd);
return 0;
}
A write in a FIFO with no reader will raise SIGPIPE and eventually returns -1 and errno set to EPIPE.
You can use lsof system command to check information about files opened by processes. Extract the FD field of the lsof command output and proceed.
For more details and example, refer this link
In your case, to get the number of process listening to your fifo, try executing the below system command.
lsof /tmp/fifo_pipe | grep [0-9]r | wc -l
In C you can implement something like this:
int i = 0;
FILE *fp;
char *command = "lsof /tmp/rjfifo | grep [0-9]r | wc -l";
fp = popen(command,"r");
if (fp != NULL){
fscanf(fp,"%d",&i);
}
fclose(fp);
printf("Number of processes reading /tmp/fifo_pipe = %d \n",i);
I am trying to write program which part is communication using named pipe (fifo). When I am running writer and reader program in infinite loop (writer in background) in bash script, some time writer program is not closing properly by what I receive bad results.
There is a simple code which I try to use in my program too:
writer.c
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int fd;
char * myfifo = "/tmp/myfifo";
/* create the FIFO (named pipe) */
mkfifo(myfifo, 0666);
/* write "Hi" to the FIFO */
fd = open(myfifo, O_WRONLY);
write(fd, "Hi", sizeof("Hi"));
close(fd);
/* remove the FIFO */
unlink(myfifo);
return 0;
}
reader.c
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#define MAX_BUF 1024
int main()
{
int fd;
char * myfifo = "/tmp/myfifo";
char buf[MAX_BUF];
/* open, read, and display the message from the FIFO */
fd = open(myfifo, O_RDONLY);
read(fd, buf, MAX_BUF);
printf("Received: %s\n", buf);
close(fd);
return 0;
}
run.sh
#!/bin/bash
while true; do
./writer &
./reader
done
Could you help me to do this properly or maybe have you another idea how to do this?
Regards
I'm trying to write simple client and server C programs, communicating with each other in separate terminals.
The server has to create a public fifo and wait for the client. Meanwhile the client is creating his own fifo through which the server's response will come. The task of the client is sending the server a name created by the queue and get in return the result of the ls command.
I did search for an answer, for example: fifo-server-program, example-of-using-named-pipes-in-linux-bash, how-to-send-a-simple-string-between-two-programs-using-pipes. I started with the code from the third link and slowly modified it.
What I've got now, is a client taking input from the user, sending it to the server and receiving it back. But it only works once. I have no idea why. The body of main function is below. I will be grateful for any help.
EDIT:
I got it working! :D The codes are below, maybe it will help someone.
The server.c code:
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char* argv[])
{
int fds[2];
char tab[BUFSIZ];
int fd, n;
char *myfifo = "/tmp/serwer";
char *myfifo2 = "/tmp/client";
pipe(fds);
mkfifo(myfifo,0666);
while(1)
{
fds[0]=open(myfifo2,O_RDONLY);
fds[1]=open(myfifo,O_WRONLY);
read(fds[0],tab,BUFSIZ);
if (strcmp("klient",tab)==0) {
printf("Od klienta: %s\n",tab);
fd=open(tab,O_WRONLY);
if(fork()==0)
{
dup2(fds[1],1);
close(fds[1]);
execlp("ls","ls","-l",NULL);
close(fds[0]);
close(fds[1]);
}
else
{
dup2(fds[0],0);
n = read(fds[0],tab,BUFSIZ);
write(fd,tab,n);
close(fds[0]);
close(fds[1]);
}
}
memset(tab, 0, sizeof(tab));
close(fd);
close(fds[0]);
close(fds[1]);
}
unlink(myfifo);
return 0;
}
The client.c code:
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(int argc, char* argv[])
{
int fds[2];
char *myfifo = "/tmp/serwer";
char *myfifo2 = "/tmp/client";
mkfifo(myfifo2,0666);
fds[0]=open(myfifo,O_RDONLY);
fds[1]=open(myfifo2,O_WRONLY);
char tab[BUFSIZ];
memset(tab, 0, sizeof(tab));
write(fds[1],"klient",6);
perror("Write:"); //Very crude error check
read(fds[0],tab,sizeof(tab));
perror("Read:"); // Very crude error check
printf("Odebrano od serwera: %s\n",tab);
close(fds[0]);
close(fds[1]);
unlink(myfifo2);
return 0;
}
Why don't you just manage both fifo's in the server? Simply changing your code to do this makes it work correctly.
If you actually want to have a client-server relationship, with a server serving many different clients, sockets would probably be a better choice.
client.cpp
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
int client_to_server;
char *myfifo = "/tmp/client_to_server_fifo";
int server_to_client;
char *myfifo2 = "/tmp/server_to_client_fifo";
char str[BUFSIZ];
printf("Input message to serwer: ");
scanf("%s", str);
/* write str to the FIFO */
client_to_server = open(myfifo, O_WRONLY);
server_to_client = open(myfifo2, O_RDONLY);
write(client_to_server, str, sizeof(str));
perror("Write:"); //Very crude error check
read(server_to_client,str,sizeof(str));
perror("Read:"); // Very crude error check
printf("...received from the server: %s\n",str);
close(client_to_server);
close(server_to_client);
/* remove the FIFO */
return 0;
}
server.cpp
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
int main()
{
int client_to_server;
char *myfifo = "/tmp/client_to_server_fifo";
int server_to_client;
char *myfifo2 = "/tmp/server_to_client_fifo";
char buf[BUFSIZ];
/* create the FIFO (named pipe) */
mkfifo(myfifo, 0666);
mkfifo(myfifo2, 0666);
/* open, read, and display the message from the FIFO */
client_to_server = open(myfifo, O_RDONLY);
server_to_client = open(myfifo2, O_WRONLY);
printf("Server ON.\n");
while (1)
{
read(client_to_server, buf, BUFSIZ);
if (strcmp("exit",buf)==0)
{
printf("Server OFF.\n");
break;
}
else if (strcmp("",buf)!=0)
{
printf("Received: %s\n", buf);
printf("Sending back...\n");
write(server_to_client,buf,BUFSIZ);
}
/* clean buf from any data */
memset(buf, 0, sizeof(buf));
}
close(client_to_server);
close(server_to_client);
unlink(myfifo);
unlink(myfifo2);
return 0;
}
It only works once because of how named pipes work. Each time you open a named pipe for read you block until another process opens it for write. Then you are paired up and the file descriptor connects your processes. Once either end closes that connection that's the end of that pipe. In order for your server to "accept another connection" it needs to move the open and close of the pipes into its main loop so it can be paired up over and over.