connecting a C program with python3 with pipes - c

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.

Related

Bidirectional processes by FIFO pipeline

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

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

Executable for the writer file with mkfifo halts

In my understanding, according to the https://linux.die.net/man/3/mkfifo,
I got an implication that I must have reader and writer file, in order to
utilize the pipe file. The source below is the writer file,
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
int main(){
int fd;
char *myfifo = "./myfifo";
mkfifo(myfifo, 0777);
fd = open(myfifo, O_WRONLY);
int PID = fork();
if(PID == 0){
execl("./reader.o", "reader", (char*)NULL);
}
write(fd, "Rock and roll baby\0", sizeof("Rock and roll baby"));
close(fd);
unlink(myfifo);
return 0;
}
and the source being provided below is for the reader file.
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUF 1024
int main(){
int fd;
char* myfifo = "./myfifo";
char buf[MAX_BUF];
fd = open(myfifo, O_RDONLY);
read(fd, buf, MAX_BUF);
write(STDOUT_FILENO, buf, MAX_BUF);
close(fd);
exit(EXIT_SUCCESS);
return 0;
}
When run the executable for the writer file, the command prompt goes into
halt, after printing a newline. My assumption for this problem is because the
open() in the writer file is not being able to detect the pipe file,
is that the case?
Thank you.
I suggest that you should create the FIFO before the fork, but only open the FIFO after the fork. This avoids an assortment of problems. For the most part, I've used write() to report errors to standard error; it isn't as convenient as using fprintf(stderr, …) though.
Note that the writer writes a null byte at the end of the message. The reader gets the null byte, but overwrites it with a newline before writing the resulting character array (it is no longer a string; strings have a terminal null byte at the end) to standard output. If the code used <stdio.h> to write the data (e.g. printf("%s\n", buf)), it wouldn't need to replace the null byte with a newline.
writer.c
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#ifndef READER
#define READER "./reader"
#endif
int main(void)
{
char *myfifo = "./myfifo";
if (mkfifo(myfifo, 0777) != 0)
{
write(STDERR_FILENO, "Failed to create FIFO\n",
sizeof("Failed to create FIFO\n") - 1);
}
int PID = fork();
if (PID == 0)
{
execl(READER, "reader", (char *)NULL);
write(STDERR_FILENO, "Failed to execute reader\n",
sizeof("Failed to execute reader\n") - 1);
exit(EXIT_FAILURE);
}
if (PID < 0)
{
write(STDERR_FILENO, "Failed to fork\n",
sizeof("Failed to fork\n") - 1);
exit(EXIT_FAILURE);
}
int fd = open(myfifo, O_WRONLY);
if (fd < 0)
{
write(STDERR_FILENO, "Failed to open FIFO for writing\n",
sizeof("Failed to open FIFO for writing\n") - 1);
unlink(myfifo);
exit(EXIT_FAILURE);
}
write(fd, "Rock and roll baby", sizeof("Rock and roll baby"));
close(fd);
unlink(myfifo);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("Child %d exited with status 0x%.4X\n", corpse, status);
return 0;
}
reader.c
#include <fcntl.h>
#include <unistd.h>
#define MAX_BUF 1024
int main(void)
{
char* myfifo = "./myfifo";
int fd = open(myfifo, O_RDONLY);
if (fd < 0)
write(STDERR_FILENO, "Failed to open FIFO for reading\n",
sizeof("Failed to open FIFO for reading\n")-1);
else
{
char buf[MAX_BUF];
int nbytes = read(fd, buf, MAX_BUF);
if (nbytes > 0)
{
buf[nbytes-1] = '\n';
write(STDOUT_FILENO, buf, nbytes);
}
close(fd);
}
return 0;
}
Example output
Rock and roll baby
Child 43734 exited with status 0x0000
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <unistd.h>
int main(){
int fd;
char *myfifo = "./myfifo";
int PID = fork();
if(PID == 0){
execl("./reader.o", "reader", (char*)NULL);
}
mkfifo(myfifo, 0777);
fd = open(myfifo, O_WRONLY);
write(fd, "Rock and roll baby\0", sizeof("Rock and roll baby"));
close(fd);
unlink(myfifo);
return 0;
}
After having the body of the code, where the execl is, moved above the
mkfifo(),
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUF 1024
int main(){
sleep(3);
int fd;
char* myfifo = "./myfifo";
char buf[MAX_BUF];
fd = open(myfifo, O_RDONLY);
read(fd, buf, MAX_BUF);
write(STDOUT_FILENO, buf, MAX_BUF);
close(fd);
exit(EXIT_SUCCESS);
return 0;
}
and having the reader have sleep() for 3 seconds, the programs started to
work; however, does anyone know if the two programs can open() the pipe file
exactly at the same time?
Thank you.

Program using named pipe in background doesn't close properly

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

Resources