Bidirectional processes by FIFO pipeline - c

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

Related

Named pipes in C program (unix)

I have to use 3 processes in order to solve the problem.
First processes gets input from (entered via keyboard) and sends it to the second procces
The second process replaces all the vocals from the text with 12345 (a with 1, e with 2, ...). I got a well working sh script (tested it) that uses sed to do this task. I will put it here.
Thrid process outputs on the screen only the alphanumeric lines. I also got a script that uses grep to do this task and also works fine (tested it).
This processes should communicate trough a named pipe (a FIFO file) and i'm running into some difficulties sending and receiving the data trough the FIFO. When i use the write function to write the data to the FIFO it outputs the data on the screen and when i'm in the second process and i try to read the data from the FIFO it just waits for a new input entered by me.
First process:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
int main() {
char text[500]; // buffer for the inputed text
char aux[100]; // Also a buffer to save multi-line input into text buffer
char* myfifo = "myfifo";
int fd_text;
printf("\nInput: (to stop giving input just type 0 on a new line):\n");
// Forming the text
while(scanf("%[^\n]%*c", aux) == 1) {
if(strcmp(aux, "0") == 0)
break;
strcat(aux, "\n");
strcat(text, aux);
}
strcat(text, "\0");
// Everything works well reading the input
int returnValue = mkfifo(myfifo, 0666);
if(returnValue < 0) {
printf("mkfifo() failed\nerrno = %d\n", errno);
if(errno == EEXIST)
printf("That file already exists.\n");
}
if(fd_text = open(myfifo, O_WRONLY) < 0) {
printf("error while opening FIFO");
exit(0);
}
int indicator = write(fd_text, text, strlen(text) + 1);
if(indicator == 0) {
printf("error while writing to FIFO");
}
close(fd_text);
return 0;
}
Second process:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
int main() {
char text[500];
char* myfifo = "myfifo";
int fd_text2;
if (fd_text2 = open(myfifo, O_RDONLY) < 0) {
printf("error while opening FIFO");
exit(1);
}
int result = read(fd_text2, text, 500);
if (result < 0)
printf("ERROR WHILE READING FROM THE FILE\n");
printf("\n%d bytes were read from the file\n", result);
printf("\nText read from FIFO:\n%s\n", text);
// Saving the text into a txt to perfom the sed command on it
FILE *fp_replace_text;
fp_replace_text = fopen("replace_text.txt", "w");
fprintf(fp_replace_text, "%s", text);
fclose(fp_replace_text);
system("chmod 777 replace.sh");
system("./replace.sh replace_text.txt");
close(fd_text2);
unlink(myfifo);
return 0;
}
replace.sh
#!/bin/sh
sed -i 's/a/1/gi' $1
sed -i 's/e/2/gi' $1
sed -i 's/i/3/gi' $1
sed -i 's/o/4/gi' $1
sed -i 's/u/5/gi' $1
If i can figure out why communication between process 1 and 2 is not working, process 3 will be the same, so i'm not posting it anymore.
Edit:
Second Process
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main() {
char text[500];
char* myfifo = "myfifo";
int fd_text2;
if ((fd_text2 = open(myfifo, O_RDWR)) < 0) {
printf("error while opening pipe");
exit(1);
}
int result = read(fd_text2, text, 500);
if (result < 0)
printf("ERROR WHILE READING FROM THE FILE\n");
FILE *fp_replace_text;
fp_replace_text = fopen("replace_text.txt", "w");
fprintf(fp_replace_text, "%s", text);
fclose(fp_replace_text);
system("chmod 777 replace.sh");
system("./replace.sh replace_text.txt");
fp_replace_text = fopen("replace_text.txt", "r");
fread(text, 500, 1, fp_replace_text);
fclose(fp_replace_text);
write(fd_text2, text, strlen(text) + 1);
close(fd_text2);
return 0;
}
Third process
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main() {
char text[500];
char* myfifo = "myfifo";
int fd_text3;
if ((fd_text3 = open(myfifo, O_RDONLY)) < 0) {
printf("error while opening pipe");
exit(1);
}
int result = read(fd_text3, text, 500);
if (result < 0)
printf("ERROR WHILE READING FROM THE FILE\n");
FILE *fp_replace_text;
fp_replace_text = fopen("replace_text.txt", "r");
fread(text, 500, 1, fp_replace_text);
fclose(fp_replace_text);
printf("Textul final este:\n");
system("chmod 777 output.sh");
system("./output.sh replace_text.txt");
unlink(myfifo);
return 0;
}
I'm also trying to send the content of the txt filo to the third process trough FIFO (i know i could just use the txt file, but i want to use the FIFO file and read from it again). So i'm use the shell script on the txt file, i read from and and then i want to send what i read from the txt file to the thrid process to FIFO, but after i run the second process the execution stops and doesn't blocks. When i'm writing to the FIFO in the first process, it blocks until the second process reads from the FIFO. Second process keeps executing and third process can't get anything. I guess there has to be something wrong with FIFO principles, that if u want to perform input/output operations on a FIFO both ends should be opened.
The problem (which ought to have cause a warning from your compiler) is in statements like this:
if(fd_text = open(myfifo, O_WRONLY) < 0)
You seem to assume that this will be evaluated from left to right, first assigning a value to fd_text, then testing that value against 0 to give a boolean value which will determine whether to enter the if block. But in C, relational operators (like <) take precedence over assignment operators (like =). So first we compare the result of the open command to 0, then assign the boolean result of that comparison to fd_text. So the file descriptor is lost, and further attempts to reach the fifo will fail. We can correct this with a pair of parentheses:
if((fd_text = open(myfifo, O_WRONLY)) < 0)
More generally, it's a good idea to develop new functionality in isolation as much as possible. If you want to send text to a fifo and receive it, just hard-code some text in the first module, don't have all that code to read user input, and don't attempt the further step of sending the text from the second module to some other process for modification, not until the fifo is working perfectly. Small steps.

Connection many client fifo to one server fifo

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;
}

is there a way of knowing if a file descriptor opened for write has someone listening on the read side?

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);

connecting a C program with python3 with pipes

Hi so i was trying to communicate to a C "server" from python through pipes and i get a UnicodeDecodeError and i don't get why, here are both codes:
"Server" in C:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_BUF 1024
int main(){
int fd;
char * myfifo = "/tmp/myfifo";
char *menu;
// create FIFO pipe
mkfifo(myfifo, 0666);
while(1){
// open the pipe for writing, and send a message to the client
fd = open(myfifo, O_WRONLY);
//fd = open(myfifo, O_NONBLOCK);
//fd = open(myfifo, O_RDONLY);
menu = "conectado a servidor con PIPE Escribe 'exit' para desconexión\n";
write(fd, menu, 1000);
close(fd);
sleep(10);
// open the pipe for reading, and print the message received from the client
char buf[MAX_BUF];
fd = open(myfifo, O_RDONLY);
read(fd, buf, MAX_BUF);
if(strcmp("exit",buf)==0){
break;
}else{
printf("Recibido: %s\n", buf);
}
close(fd);
}
// remove the pipe
unlink(myfifo);
return 0;
}
and "Client" in python:
import os,sys,errno,pipes
def Prueba():
print ("creating pipe and connecting...")
p = pipes.Template()
fifo = "/tmp/myfifo"
f = p.open(fifo,'r')
try:
algo = f.read()
finally:
f.close()
print (algo)
and the error that i have is:
algo = f.read()
File "/usr/lib/python3.5/codecs.py", line 321, in decode
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfc in position 97: invalid start byte
any help/comment/suggestion on the code will be welcomed, thanks in advance
You're getting garbage after your text because you're sending like this:
write(fd, menu, 1000);
The 1000 should be strlen(menu) + 1 to send a null-terminated string, for example.

Pipe cannot read Enter key (C , Linux)

I a beginner and I am writing a bi-direction communication programme in C, Linux for assignment submission. However, I've test and found that "enter" key is not readable via pipe as it contains 0 byte. If I accidentally press enter before normal characters are typed, the 2 screens turn to deadlock and cannot communicate. I tried getchar() or check the byte=0, but I don't know which position I should put the command to make it works. Any Ideas? Thanks
(Below is sender, I want the programme can send and receive msg)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main()
{ char pipename1[] = "/tmp/pipe1"; /* pathname of the named pipe */
char buf1[80];
char pipename2[] = "/tmp/pipe2"; /* pathname of the named pipe */
char buf2[80];
int i, n1,n2, fd1, fd2;
mkfifo(pipename1,0666);
printf("Please run receiver in other putty. \n");
fd1 = open(pipename1,O_WRONLY);
fd2 = open(pipename2,O_RDONLY);
while(1){
printf("Please enter a message. <To check message, press Enter>\n");
n1 = read(STDIN_FILENO,buf1,80); /* read a line */
if (n1 <= 0) break;
buf1[--n1] = 0;
write(fd1,buf1,n1); /* send the string */
while ((n2 = read(fd2,buf2,80)) > 0) { /* read from pipe */
buf2[n2] = 0;
printf("\n <player2> [%s] \n",buf2,n2);
break;}
}
close(fd1);
close(fd2);
unlink(pipename1);
unlink(pipename2);
exit(0); }
(Edited) Actually I created another end to read msg, code is below
int main()
{ char pipename1[] = "/tmp/pipe1"; /* pathname of the named pipe */
char buf1[80];
char pipename2[] = "/tmp/pipe2"; /* pathname of the named pipe */
char buf2[80];
int i, n1,n2, fd1, fd2;
mkfifo(pipename2,0666); /* make file with the file name defined in pipename1, 0666 is permission every one can read & write */
printf("Please run receiver programme in another browser\n");
fd1 = open(pipename1,O_RDWR);
fd2 = open(pipename2,O_RDWR);
while(1){
printf("<Please enter a message.\n");
n2 = read(STDIN_FILENO,buf2,80); /* read a line */
if (n2 <= 0) break;
buf2[--n2] = 0;
write(fd2,buf2,n2); /* send the string */
while ((n1 = read(fd1,buf1,80)) > 0) { /* read from pipe */
buf1[n1] = 0;
printf("\n <player1>[%s]\n",buf1,n1);
break;}
}
close(fd1);
close(fd2);
exit(0);
}
The problem is that you write to the pipe (using fd1) but you don't read from it. Instead you open a totally unrelated filed and attempt to read from it.
A named pipe in the file-system is the single file initialized by mkfifo, and as all other pipes it has a write-end and a read-end, and both ends are accessed by opening the same file.

Resources