Linux message sender and receiver execute error(repetition error) - c

I worked in Linux.
I only want to print the message on receiver when Sanders sends.
but, the receiver continues to output same message.
I exactly want to get message in receiver, only if sender sends message.
This code is my code.
I try to conditional, but it's not easy. help
//Sender
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main()
{
int fd;
char message[100];
printf("Enter \"exit\" to stop: \n");
while(1)
{
fd=open("/home/control/work/io_dev",O_RDWR); //open file
if (fd ==-1) {
printf("Device open error");
exit(1);
}
sleep(1);
write(fd,message,sizeof(message));
printf("Sender>>");
fgets(message,sizeof(message),stdin);// input message
write(fd,message, sizeof(message));//write on file
if(strcmp(message,"exit\n")==0)
break;
write(fd,message,sizeof(message));
close(fd); //file close
}
}
//Receiver
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
int main()
{
int fd;
char message[100];
while(1){
sleep(1);
fd=open("/home/control/work/io_dev",O_RDWR|O_CREAT); // open or create file
if (fd == -1) { //when file open error occurs
printf("Device open error");
exit(1);
}
read(fd, message, sizeof(message));//read file
sleep(1);//wait
if(strcmp(message,"exit\n") ==0)//loop off
break;
if(message[0]!='\0'){
printf("Received>> %s",message);//print
}
write(fd,message,sizeof(message));
close(fd);//file close
sleep(3);
}
}

Delete the first "write(fd,message,sizeof(message));" in sender side.
Delete "if(message[0]!='\0')"in receiver side.

the following proposed code, for receiver
cleanly compiles
performs the desired functionality
properly checks for errors
avoids having to continually open/close the I/O device
echos what was actually received rather than the whole receiver buffer, much of which may contain trash
avoids the use of 'magic' numbers in the code
and now, the proposed code:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#define MAX_MSG_LEN 100
int main( void )
{
int fd;
char message[ MAX_MSG_LEN ];
fd=open("/home/control/work/io_dev",O_RDWR|O_CREAT, 0666 ); // open or create file
if (fd == -1)
{ //when file open error occurs
printf("Device open error");
exit(1);
}
while(1)
{
ssize_t bytesRead = read(fd, message, sizeof(message));//read file
if( bytesRead <0 )
{
// handle error and exit
perror( "read failed" );
close( fd );
break;
}
if( bytesRead == 0 )
{ // sender closed the connection
// clean up and exit
close( fd );
break;
}
message[ bytesRead ] = '\0';
if(strcmp(message,"exit\n") ==0)//loop off
break;
printf("Received>> %s",message);//print
if( write(fd,message,strlen(message)) != strlen( message ) )
{
// handle incomplete message write
}
}
close(fd);//file close
}
HOWEVER, if your trying to 'pace' the read/write operations with multiple readers and writers; then strongly suggest using a mutex to avoid any 'race' conditions and maybe even mkfifo() for creating the file. Remember to (before exiting the program) to destroy the fifo.
If deciding to use a FIFO, then be sure to call unlink( filename ); so the file will be destroyed when the program exits
If you want to keep the repeated open/close in the while() loop, then use O_EXCL rather than O_CREAT so the separate programs cannot step on each other.

Related

fifo linux - write() function terminates the program abruptly

I'm implementing a pipe in C, where multiples producer programs (9 in my case) write data to one single consumer program.
The problem is that some producers (some times one or two) exit the program abruptly when calling the write() function.
The code is simple, here is the producer code:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#define MSG_SIZE_BYTES 4
void send(unsigned int * msg){
int fd, msg_size;
int r;
char buffer [5];
char myfifo[50] = "/tmp/myfifo";
fd = open(myfifo, O_WRONLY);
if(fd == -1){
perror("error open SEND to fifo");
}
r = write(fd, msg, MSG_SIZE_BYTES);
if(r == -1){
perror("error writing to fifo");
}
close(fd);
printf("Message send\n");
}
int main(int argc, char *argv[]){
int cluster_id = atoi(argv[1]);
unsigned int msg[1];
msg[0] = cluster_id;
while(1){
printf("Press a key to continue...\n");
getchar();
send(msg);
}
}
And here is the consumer code
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#define MSG_SIZE_BYTES 4
int receive(unsigned int * received_msg){
int fd, msg_size;
int ret_code;
char buffer [5];
char myfifo[50] = "/tmp/myfifo";
fd = open(myfifo, O_RDONLY);
if(fd == -1)
perror("error open RECV to fifo");
ret_code = read(fd, received_msg, MSG_SIZE_BYTES);
close(fd);
if (ret_code == -1){
printf("\nERROR\n");
return 0;
}
return 1;
}
void main(){
mkfifo("/tmp/myfifo", 0666);
unsigned int msg[1];
while(1){
receive(msg);
printf("receive msg from id %d\n", msg[0]);
}
}
I'm compiling the producers and consumer with the following command: gcc -o my_progam my_program.c
To reproduce the problem, you need to open 9 terminals to run each producer and 1 terminal to run the consumer.
Execute the consumer: ./consumer
Execute the producer in all terminals simultaneously, passing to each execution an associated ID passed by command line. Ex: ./producer 0, ./producer 1.
After the producer send messages some times (10 in average), one arbitrary producer will abruptly stop its execution, showing the problem.
The following image depicts the execution:
Terminals ready to execute
The following image depicts the error on producer ID 3
Error on producer 3
Thanks in advance
It looks like the consumer program closes the reading end of the pipe after reading data:
fd = open(myfifo, O_RDONLY);
if(fd == -1){
perror("error open RECV to fifo");
}
ret_code = read(fd, received_msg, MSG_SIZE_BYTES);
close(fd);
All other writers, which are currently trying to write() data (i.e. are blocked in the write()-syscall) now receive a SIGPIPE, which leads to program termination (if no other signal handling is specified).
Your consumer program may not close the filedescriptor while producers are writing. Just read the next datum without closing.
Problem SOLVED:
The problem is that I was opening and closing the FIFO at each message, generating a Broken pipe in some write attempts. Removing the close() and inserting the open() function for BOTH producer and consumer at the begging of the code instead inside the loop solved the problem.
Here is the code of producer with the bug fixed:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#define MSG_SIZE_BYTES 4
int my_fd;
void send(unsigned int * msg){
int fd, msg_size;
int r;
char buffer [5];
char myfifo[50] = "/tmp/myfifo"
if(fd == -1){
perror("error open SEND to fifo");
}
r = write(my_fd, msg, MSG_SIZE_BYTES);
if(r == -1){
perror("error writing to fifo");
}
//close(fd);
printf("Message send\n");
}
int main(int argc, char *argv[]){
int cluster_id = atoi(argv[1]);
unsigned int msg[1];
msg[0] = cluster_id;
my_fd = open("/tmp/myfifo", O_WRONLY);
while(1){
printf("Press a key to continue...\n");
getchar();
send(msg);
}
}
And here is the consumer code:
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#define MSG_SIZE_BYTES 4
int my_fd;
int receive(unsigned int * received_msg){
int fd, msg_size;
int ret_code;
char buffer [5];
char myfifo[50] = "/tmp/myfifo";
if(fd == -1)
perror("error open RECV to fifo");
ret_code = read(my_fd, received_msg, MSG_SIZE_BYTES);
//close(fd);
if (ret_code == -1){
printf("\nERROR\n");
return 0;
}
return 1;
}
void main(){
mkfifo("/tmp/myfifo", 0666);
my_fd = open("/tmp/myfifo", O_RDONLY);
unsigned int msg[1];
while(1){
receive(msg);
printf("receive msg from id %d\n", msg[0]);
}
}
Thank you all!!

Named PIPE (FIFO) reading content of file in C

Basically I want my client program to read data from a file (file name/path specified in the command line input) and copy that data to the FIFO and I want my server program to read from the FIFO and print every line.
For example if I want to print the contents of the /etc/passwd text file I run the program in the terminal in this way:
./server &
./client < /etc/passwd
However, instead of printing any output, it prints out nothing but 'done'.
Why?
Here's my code:
server.c
//server.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define FIFONAME "myfifo"
int main(void){
int n,fd;
char buffer[1024];
unlink(FIFONAME);
//create FIFO
if(mkfifo(FIFONAME,0666)<0){
perror("server: mkfifo");
exit(1);
}
//open FIFO for reading
if((fd = open(FIFONAME, O_RDONLY))<0){
perror("server: open");
exit(1);
}
//READ from fifo UNTIL end of tile and print
//what we get on the standard input
while((n=read(fd,buffer,sizeof(buffer)))>0){
write(1, buffer, n);
}
close(fd);
exit(0);
}
.
client.c
//client.c
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define FIFONAME "myfifo"
int main(void){
int n,fd;
char buffer[1024];
/* open, read, and display the message from the FIFO */
if((fd = open(FIFONAME, O_WRONLY))<0){
perror("client: open");
exit(1);
}
//read from standard input and copy data to the FIFO
while (fgets(buffer, sizeof(buffer), stdin) != 0){
fgets(buffer, sizeof(buffer), stdin);
write(fd, buffer, n);
}
close(fd);
exit(0);
}
this code is wrong:
while (fgets(buffer, sizeof(buffer), stdin) != 0){
fgets(buffer, sizeof(buffer), stdin);
write(fd, buffer, n);
this loops consumes the input, then reads it again. You're losing the first (and possibly the only) buffer. I would do (maybe not the best code but works):
while (1){
if (fgets(buffer, sizeof(buffer), stdin)==0) break;
write(fd, buffer, n);
}
Aside, as noted in my comments, running the server in background to create the FIFO and running the client without waiting for the FIFO to be created is a potential race condition.

Reader-process termination on FIFO-file closing

I've written a simple reader-writer pair of programs. Writer creates/opens a FIFO-file and is constantly writing a string into it. The reader is just reading it and writing to stdout. The reader does so only for 10 times and then quits. Surprisingly (for me) the writer almost immediately exits too. It does not just go out of writing loop, it seems to jump out of it, I can tell it by not seeing the final "byebye" on the screen. I could sort of accept such behaviour, but I still can't understand why.
Could someone please kindly share their knowledge with me?
/* writer code */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
char msg [] = "Leo_Tolstoy";
size_t len = strlen("Leo_Tolstoy");
if (mkfifo ("myfifo", 0600) != 0) {
perror ("creating fifo");
}
int fd;
if ( (fd = open ("myfifo", O_WRONLY)) == -1) {
perror ("opening fifo");
exit (1);
}
while (1)
{
int r = write (fd, msg, len);
if (r == -1)
perror ("writing");
sleep(1);
}
printf ("byebye\n");
close (fd);
return 0;
}
/* reader code */
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/shm.h>
int main()
{
char buf[50];
printf ("bef opening\n");
int fd = open ("myfifo", O_RDONLY);
if (fd == -1) {
perror ("opening fifo");
exit (1);
}
printf ("bef reading\n");
int cnt=0;
while (cnt < 10)
{
int r = read (fd, buf, 50);
if (r == 0)
break;
if (r == -1)
perror ("reading");
write (1, buf, r);
cnt++;
}
// close (fd);
return 0;
}
When the exits (after 10 iterations), the writer receives a SIGPIPE due to the read end being closed. So, the default action for the signal SIGPIPE is executed which to terminate the program. That's why you don't see the final printf() is not executed.
Instead you could ignore (SIG_IGN) the signal SIGPIPE in the writer by calling sigaction() and then handle the write error yourself.

IPC FIFO Producer-Consumer Deadlock

This is the producer.
// speak.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define FIFO_NAME "american_maid"
int main(void)
{
char s[300];
int num, fd;
mknod(FIFO_NAME, S_IFIFO | 0666, 0);
printf("waiting for readers...\n");
fd = open(FIFO_NAME, O_WRONLY);
printf("got a reader--type some stuff\n");
while (gets(s), !feof(stdin)) {
if ((num = write(fd, s, strlen(s))) == -1)
perror("write");
else
printf("speak: wrote %d bytes\n", num);
}
return 0;
}
And this is the consumer.
//tick.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define FIFO_NAME "american_maid"
int main(void)
{
char s[300];
int num, fd;
mknod(FIFO_NAME, S_IFIFO | 0666, 0);
printf("waiting for writers...\n");
fd = open(FIFO_NAME, O_RDONLY);
printf("got a writer\n");
do {
if ((num = read(fd, s, 300)) == -1)
perror("read");
else {
s[num] = '\0';
printf("tick: read %d bytes: \"%s\"\n", num, s);
}
} while (num > 0);
return 0;
}
When I run them, Producer outputs,
waiting for readers...
And consumer outputs,
waiting for writers...
speak doesn't find the reader, tick. As from the theory here I got that, open() (speak.c) will be keep blocked until open() (tick.c) is opened. And the vice versa. So I guess there a deadlock or something happening. I need a solution of this.
It looks like you have a race condition between the reader and the writer.
To fix this, you need a method of not launching the reader until the writer is "active". For this, I'd suggest making a pipe and writing to it when the writer is ready. Then, when reading from the read end of the fork succeeds, the fifo is prepared and the reader should work.
You need to use forks here because coordinating mutexes between a parent and a child process is non-trivial and properly done pipes is easier.
Also, you called mknod() twice. Granted, it'll return -1 with errno == EEXIST, but be more careful. To avoid this, make the reader and writer a function that takes a path as an argument.
Rewrite your writer as int speak(const char *fifo, int pipefd) and your reader as int tick(const char *fifo).
Then make a wrapper like this:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
const char fifo_name[] /* = ... */;
int speak(const char *fifo, int pipefd);
int tick(const char *fifo);
int main() {
int pipefd[2];
pipe(pipefd);
mknod(fifo_name, S_IFIFO | 0666, 0);
if (fork() == 0) {
close(pipefd[0]);
return speak(fifo_name, pipefd[1]);
} else {
close(pipefd[1]);
char foo;
read(pipefd[0], &foo, 1);
return tick(fifo_name);
}
}
Modify your writer to print a byte (of anything) to the passed fd after the fifo is created (i.e. right after the call to open(..., O_WRONLY)).
Don't use my code verbatim, as I've omitted error checking for the sake of brevity.
it runs ok in my env. and if reader and writer is ready, open will return. because open is blocked, so in my opinion, mknod function is success. May be you excute these two process at different path.

Proper FIFO client-server connection

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.

Resources