How to write and read from a named pipe in C? - c

I have 2 programs (write.c and read.c). I want to continuously write to the named pipe from standard input, and read from it on the other end (and write to standard output). I've made something work, but it isn't working right. The program on the other end reads in the wrong order or reads special characters (so it reads more then it needs?). I also want to be able to compare the named pipe output to a certain string.
Anyways, here's the code from both files:
write.c:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define BUFFSIZE 512
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
void main()
{
int fd, n;
char buf[BUFFSIZE];
mkfifo("fifo_x", 0666);
if ( (fd = open("fifo_x", O_WRONLY)) < 0)
err("open")
while( (n = read(STDIN_FILENO, buf, BUFFSIZE) ) > 0) {
if ( write(fd, buf, strlen(buf)) != strlen(buf)) {
err("write");
}
}
close(fd);
}
read.c:
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFSIZE 512
#define err(mess) { fprintf(stderr,"Error: %s.", mess); exit(1); }
void main()
{
int fd, n;
char buf[BUFFSIZE];
if ( (fd = open("fifo_x", O_RDONLY)) < 0)
err("open")
while( (n = read(fd, buf, BUFFSIZE) ) > 0) {
if ( write(STDOUT_FILENO, buf, n) != n) {
exit(1);
}
}
close(fd);
}
Example of input:
hello how are you
123
test
Example of incorrect output:
hello how are you
b123
o how are you
btest
how are you
b
Another example of input:
test
hi
And output:
test
hi
t

The buffer modify by read is not a valid c string so
write(fd, buf, strlen(buf)) != strlen(buf) // write.c
is undefined behaviour. You should do
write(fd, buf, n) != n
because you read n octet with read().
It's funny because you do it for read.c but not for write.c
The type of n must but ssize_t and not int, man read.
main() must return a int Declare main prototype

Related

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.

Reading and searching files using systemcalls in C

I tried reading from the file "hello.txt" but it doesn't enter the while loop at all. The read function returns 0 on EOF and -1 on error. I'm trying to search for the word in w if it exists in the file or not. I'm reading characters from the file and comparing them to w[].
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd;
char c;
int i=0;
int bytesread;
int flag=1;
char w[]={'h','e','l','l','o'};
if((fd=open("hello.txt",O_RDONLY,0))!=-1){ //if 1
bytesread = read(fd,&c,0);
if(bytesread!=-1){ //if 2
while(bytesread!=0)
{ //while
if(c==w[i])
{ //if 3
i++;
flag=0;
} //end of f3
else if(flag==0&&i!=0)
{ // else 3
i=0;
flag=1;
} // end of else 3
bytesread = read(fd,&c,0);
} //end of while
}else //end of if 2
printf("couldn't read file.\n");
}else //end of if 1
printf("Couldn't open file for read.\n");
} //end of main
ssize_t read(int fd, void *buf, size_t count);
read reads count bytes from the file. You're asking it to read zero bytes when doing bytesread = read(fd,&c,0);. Change it to bytesread = read(fd,&c,1);
Try this:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{
int fd;
char c;
int bytesread;
if ((fd = open("hello.txt", O_RDONLY, 0)) != -1) {
while ((bytesread = read(fd, &c, 1)) == 1)
printf("read %d bytes [%c]\n", bytesread, c);
} else
printf("Couldn't open file for read.\n");
return 0;
}
read(fd,&c,0) asks the system to read zero bytes, and it shouldn't be what you want to do.
You should ask the system to read one byte by read(fd,&c,1).

How to send a file through a named pipe in C?

I have two programs, server and client. Server should read a file and then send its content through a named pipe to client. But my server reads only two chars from file, and then exits. What is wrong with this code?
server.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 line[300];
int num, fd;
FILE *fp;
fp = fopen("out.txt","r");
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 (fgets(line, sizeof(line), fp)) {
if ((num = write(fd, line, strlen(line))) == -1)
perror("write");
else
printf("speak: wrote %d bytes\n", num);
}
fclose(fp);
return 0;
}
client.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 the code shown below using the command sequence:
$ ln -s server.c out.txt
$ ./client &
$ ./server
$
I get a copy of the source code printed by the client program. Similarly when I run the commands using:
$ ./server &
$ ./client
$
The revised code is not modified all that significantly. It avoids do { } while(...) loops — they're so seldom really beneficial — and is very careful about not overflowing buffers. The code also has superfluous headers removed.
server.c
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define FIFO_NAME "american_maid"
int main(void)
{
const char infile[] = "out.txt";
FILE *fp = fopen(infile, "r");
if (fp == 0)
{
fprintf(stderr, "Failed to open %s for reading", infile);
return(1);
}
mknod(FIFO_NAME, S_IFIFO | 0666, 0);
printf("waiting for readers...\n");
int fd = open(FIFO_NAME, O_WRONLY);
if (fd > 0)
{
char line[300];
printf("got a reader--type some stuff\n");
while (fgets(line, sizeof(line), fp))
{
int len = strlen(line);
int num = write(fd, line, len);
if (num != len)
perror("write");
else
printf("speak: wrote %d bytes\n", num);
}
close(fd);
}
fclose(fp);
return 0;
}
client.c
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#define FIFO_NAME "american_maid"
int main(void)
{
const char outfile[] = "client.out";
FILE *fp = fopen(outfile, "w");
if (fp == 0)
{
fprintf(stderr, "Failed to open %s for writing\n", outfile);
return 1;
}
printf("waiting for writers...\n");
mknod(FIFO_NAME, S_IFIFO | 0666, 0);
int fd = open(FIFO_NAME, O_RDONLY);
if (fd > 0)
{
int num;
char s[300];
printf("got a writer\n");
while ((num = read(fd, s, sizeof(s))) > 0)
{
printf("tick: read %d bytes: \"%.*s\"\n", num, num, s);
fprintf(fp, "%.*s", num, s);
}
close(fd);
}
fclose(fp);
return 0;
}
Note that this version writes its output to file client.out; even when given a file with some very long lines to process (2049 bytes including the newline at the end), the output in client.out exactly matches the input in out.txt.
Remove the line mknod(FIFO_NAME, S_IFIFO | 0666, 0); from the file client.c. Then the program will work as expected. Server will create a file and sent the content of the file to fifo.

Why I'm getting trash on this pipe?

I'm running a full-duplex server/client code I found on Oracle's website:
When writing ./fd_client hahaha I get something like:
HAHAHA0�$0
The upper case is OK (it's what the server it's supposed to return) but, how the hell do I avoid that trailing trash?
fd_client.c
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "fullduplex.h" /* For name of the named-pipe */
int main(int argc, char *argv[])
{
int wrfd, rdfd, numread;
char rdbuf[MAX_BUF_SIZE];
/* Check if an argument was specified. */
if (argc != 2) {
printf("Usage : %s \n", argv[0]);
exit (0);
}
/* Open the first named pipe for writing */
wrfd = open(NP1, O_WRONLY);
/* Open the second named pipe for reading */
rdfd = open(NP2, O_RDONLY);
/* Write to the pipe */
write(wrfd, argv[1], strlen(argv[1]));
/* Read from the pipe */
numread = read(rdfd, rdbuf, MAX_BUF_SIZE);
rdbuf[numread] = '0';
printf("Full Duplex Client : Read From the Pipe : %s\n", rdbuf);
return 0;
}
fd_server.c
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "fullduplex.h" /* For name of the named-pipe */
int main(int argc, char *argv[])
{
int rdfd, wrfd, ret_val, count, numread;
char buf[MAX_BUF_SIZE];
/* Create the first named - pipe */
ret_val = mkfifo(NP1, 0666);
if ((ret_val == -1) && (errno != EEXIST)) {
perror("Error creating the named pipe");
exit (0);
}
ret_val = mkfifo(NP2, 0666);
if ((ret_val == -1) && (errno != EEXIST)) {
perror("Error creating the named pipe");
exit (0);
}
/* Open the first named pipe for reading */
rdfd = open(NP1, O_RDONLY);
/* Open the second named pipe for writing */
wrfd = open(NP2, O_WRONLY);
/* Read from the first pipe */
numread = read(rdfd, buf, MAX_BUF_SIZE);
buf[numread] = '0';
printf("Full Duplex Server : Read From the pipe : %s \n", buf);
/* Convert to the string to upper case */
count = 0;
while (count < numread) {
buf[count] = toupper(buf[count]);
count++;
}
/*
* Write the converted string back to the second
* pipe
*/
write(wrfd, buf, strlen(buf));
}
fullduplex.h
#define NP1 "/tmp/np1"
#define NP2 "/tmp/np2"
#define MAX_BUF_SIZE 255
Did you mean:
rdbuf[numread] = '\0';
buf in fd_server.c has the same problem.
This:
buf[numread] = '0';
is wrong. You want:
buf[numread] = '\0';
(Same with rdbuf[numread] = '0';.)
These lines produce bad output:
buf[numread] = '0';
printf("Full Duplex Server : Read From the pipe : %s \n", buf);
First, buf[numread] = '0'; Overwrites your null-terminator.
With this overwritten, printf(%s) doesn't know where to stop printing.
The null-terminator tells C where the string ends.
After you overwrote it, C no longer knows where the end of the string is, and prints your string "HAHAHA", but keeps printing garbage after that.

problem with fifos linux

I am having problem debugging why n_bytes in read_from_fifo function in client.c doesn't correspond to the value written to the fifo. It should only write 25 bytes but it tries to read a lot more (1836020505 bytes (!) to be exact). Any idea why this is happening?
server.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <sys/stat.h>
typedef enum { false, true } bool;
//first read the int with the number of bytes the data will have
//then read that number of bytes
bool read_from_fifo(int fd, char* var)
{
int n_bytes;
if (read(fd, &n_bytes, sizeof(int)))
{
printf("going to read %d bytes\n", n_bytes);
if (read(fd, var, n_bytes))
printf("read var\n");
else {
printf("error in read var. errno: %d\n", errno);
exit(-1);
}
}
return true;
}
int main()
{
mkfifo("/tmp/foo", 0660);
int fd = open("/tmp/foo", O_RDONLY);
char var[100];
read_from_fifo(fd, var);
printf("var: %s\n", var);
return 0;
}
client.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
typedef enum { false, true } bool;
//first write to fd a int with the number of bytes that will be written afterwards
bool write_to_fifo(int fd, char* data)
{
int n_bytes = (strlen(data)) * sizeof(char);
printf("going to write %d bytes\n", n_bytes);
if (write(fd, &n_bytes, sizeof(int) != -1))
if (write(fd, data, n_bytes) != -1)
return true;
return false;
}
int main()
{
int fd = open("/tmp/foo", O_WRONLY);
char data[] = "some random string abcdef";
write_to_fifo(fd, data);
return 0;
}
Help is greatly appreciated. Thanks in advance.
The return value for an error from read(2) is -1, not 0. So your if statement for the first 4-byte read, at least, is wrong.
Did you verify if nbytes printed by read_from_fifo() function displayed the correct value ?
Just notice that on write(fd, data, n_bytes) you did not write the end of string char '\0', and whenever you read it by read(fd, var, n_bytes), you did not added a '\0' to the end of string just read, so the printf("var: %s\n", var); could display a not \0 ended string resulting unpredicted results.
I have found the solution myself.
The problem is a ')' believe it or not. The n_bytes variable is correct, the problem is that I am not writing that to the fifo.
this (write(fd, &n_bytes, sizeof(int) != -1))
should be this (write(fd, &n_bytes, sizeof(int)) != -1)
Thanks anyway for your answers.

Resources