Related
Hi there i am trying to make such a program in which the the two fds stdin and fifo monitor by select() and communicate with each other.
select() will monitor either fifo ready for reading or stdin.
server.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/select.h>
int main(int argc,char *argv[]){
int f,fifo_read,fifo_write,status;
fd_set readset;
FD_ZERO(&readset);
char str[512]="start";
if(argc !=2)
if(argc != 2){
printf("\nError: %s required argument [Fifo Name]\n\n",argv[0]);
exit(EXIT_FAILURE);
}
if ((open(argv[1], O_RDWR)) < 0){
f = mkfifo(argv[1],S_IRWXU);
if(f<0){
perror("Error While Creating FIFO ");
exit(EXIT_FAILURE);
}
else
printf("FIFO Created Successfully...\n");
}
while(strcmp(str,"end")!=0){
fifo_write= open(argv[1],O_WRONLY);
FD_SET(fifo_read, &readset);
FD_SET(STDIN_FILENO, &readset);
status = select(fifo_read+1, &readset, NULL, NULL, NULL);
if(status==-1){
perror("Error While Calling select() system call ");
//exit(EXIT_FAILURE);
}
if(FD_ISSET(STDIN_FILENO,&readset)){
if(fifo_write<0)
perror("\nError while writing on pipe ");
else{
printf("\nServer>> ");
scanf("%s",str);
write(fifo_write,str,strlen(str));
close(fifo_write);
}
}
fifo_read=open(argv[1],O_RDONLY);
if(FD_ISSET(fifo_read,&readset)){
if(fifo_read<0)
perror("\nError while reading from pipe ");
else{
read(fifo_read,str,strlen(str));
close(fifo_read);
printf("\nJiya%s",str);
}
}
}
return 0;
}
client.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <sys/select.h>
int main(int argc,char *argv[]){
int f,fifo_read,fifo_write,status;
fd_set readset;
FD_ZERO(&readset);
char str[512]="start";
while(strcmp(str,"end")!=0){
fifo_write= open(argv[1],O_WRONLY);
FD_SET(fifo_read, &readset);
FD_SET(STDIN_FILENO, &readset);
status = select(fifo_read+1, &readset, NULL, NULL, NULL);
if(status==-1){
perror("Error While Calling select() system call ");
//exit(EXIT_FAILURE);
}
if(FD_ISSET(fifo_read,&readset)){
if(fifo_read<0)
printf("\nError opening read pipe");
else{
read(fifo_read,str,strlen(str));
close(fifo_read);
printf("\n%s",str);
}
}
fifo_read=open(argv[1],O_RDONLY);
if(FD_ISSET(STDIN_FILENO,&readset)){
if(fifo_write<0)
printf("\nError opening write pipe");
else{
printf("\nClient>> ");
scanf("%s",str);
write(fifo_write,str,strlen(str));
close(fifo_write);
}
}
}
return 0;
}
I have posted a working, somewhat simplified version of your code below. This code reads from STDIN in the client and sends that input through the pipe created by mkfifo to the server. The server loops reading from its end of the pipe and echoes what it read to STDOUT.
Client output:
CLIENT > Message1
CLIENT > Message2
CLIENT > Yet another message.
CLIENT > A fourth message, but this one is quite a bit longer than the first messages.
CLIENT > end
Server output:
SERVER: Got 8 byte message: 'Message1'
SERVER: Got 8 byte message: 'Message2'
SERVER: Got 20 byte message: 'Yet another message.'
SERVER: Got 77 byte message: 'A fourth message, but this one is quite a bit longer than the first messages.'
EOF encountered...
I'll highlight some of the main differences:
I first create the pipe special file via mkfifo in the server. I then open the special file in the server and the client. This happens before the loop, and the file descriptors stay open during the loop instead of being repeatedly opened and closed.
The client only writes to the pipe and the server only reads from the pipe. At least on Linux, pipes are unidirectional (pipe man page: Pipes and FIFOs (also known as named pipes) provide a unidirectional interprocess communication channel. A pipe has a read end and a write end...) Two pipes may be used for bidirectional communication on Linux, and even on systems that support bidirectional pipes, using two pipes would still be supported and would be more portable.
When calling read, you should use the total size of the str buffer, not strlen(str). Also, str should be cleared between reads, so as to not contain old data (memset in new code).
I used fgets instead of scanf.
After the server opens the FIFO, I unlink the file, so that it is automatically deleted from the file system. The underlying file object will still exist until processes using it have terminated. This is optional.
Server:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int fifo_read = -1;
char str[512]= "";
fd_set readset;
FD_ZERO(&readset);
if (argc != 2) {
printf("Usage: %s FIFO_NAME\n", argv[0]);
exit(EXIT_FAILURE);
}
/* Server will make the FIFO, both sides will open it */
if (mkfifo(argv[1], S_IRWXU) == -1) {
perror("mkfifo()");
exit(EXIT_FAILURE);
}
if ((fifo_read = open(argv[1], O_RDONLY)) == -1) {
perror("open()");
exit(EXIT_FAILURE);
}
if (unlink(argv[1]) == -1) {
perror("unlink()");
exit(EXIT_FAILURE);
}
while (1) {
FD_SET(fifo_read, &readset);
if (select(fifo_read + 1, &readset, NULL, NULL, NULL) == -1) {
perror("select()");
exit(EXIT_FAILURE);
}
if (FD_ISSET(fifo_read, &readset)) {
ssize_t bytes_read;
memset(str, 0, sizeof(str));
bytes_read = read(fifo_read, str, sizeof(str));
if (bytes_read == -1) {
perror("read()");
exit(EXIT_FAILURE);
}
else if (bytes_read == 0) {
printf("EOF encountered...\n");
break;
}
printf("SERVER: Got %ld byte message: '%s'\n", bytes_read, str);
}
}
if (close(fifo_read) == -1) {
perror("close()");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
Client:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int fifo_write = -1;
char str[512] = "";
fd_set readset;
FD_ZERO(&readset);
if (argc != 2) {
printf("Usage: %s FIFO_NAME\n", argv[0]);
exit(EXIT_FAILURE);
}
if ((fifo_write = open(argv[1], O_WRONLY)) == -1) {
perror("open()");
exit(EXIT_FAILURE);
}
while (1) {
printf("CLIENT > ");
fflush(stdout);
FD_SET(STDIN_FILENO, &readset);
if (select(STDIN_FILENO + 1, &readset, NULL, NULL, NULL) == -1) {
perror("select()");
exit(EXIT_FAILURE);
}
if (FD_ISSET(STDIN_FILENO, &readset)) {
memset(str, 0, sizeof(str));
if (!fgets(str, sizeof(str), stdin)) {
printf("fgets() failed to read a line.\n");
exit(EXIT_FAILURE);
}
// See https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input
str[strcspn(str, "\r\n")] = 0;
if (strcmp(str, "end") == 0) {
break;
}
if (write(fifo_write, str, strlen(str)) == -1) {
perror("write()");
exit(EXIT_FAILURE);
}
}
}
if (close(fifo_write) == -1) {
perror("close()");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
Here i Got the Solution :)
server.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/select.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
int main(int argc, char *argv[])
{
if(argc != 2){
printf("\nError: %s required argument [Fifo Name]\n\n",argv[0]);
exit(EXIT_FAILURE);
}
int fd,wr,rd,ret;
fd_set readset;
if(mkfifo(argv[1],S_IRWXU)==-1){
if(errno!=EEXIST)
perror("Error unable to create FIFO ");
else
perror("Error unable to create FIFO ");
exit(EXIT_FAILURE);
}
else
printf("FIFO created Successfully!\n\n");
fd = open(argv[1],O_RDWR);
if(fd==-1){
perror("Error Failed to open fifo\n");
exit(EXIT_FAILURE);
}
while(!0){
FD_ZERO(&readset);
FD_SET(fd,&readset);
FD_SET(STDIN_FILENO,&readset);
sleep(1);
ret = select(fd+1,&readset,NULL,NULL,NULL);
if(ret==-1){
perror("Error select() ");
exit(EXIT_FAILURE);
}
char str[512]="";
if(FD_ISSET(STDIN_FILENO,&readset)){
//fprintf(stderr, ">> ");
rd = read(STDIN_FILENO,str,sizeof(str));
if(rd==-1){
perror("Error while reading from fifo");
exit(EXIT_FAILURE);
}
char temp[512]="Server :: ";
strcat(temp,str);
wr = write(fd,temp,sizeof(temp));
if(wr==-1){
perror("Error while writing to fifo ");
exit(EXIT_FAILURE);
}
continue;
}
if(FD_ISSET(fd,&readset)){
rd = read(fd,str,sizeof(str));
if(rd==-1){
perror("Error while reading from fifo");
exit(EXIT_FAILURE);
}else if(rd==0)
continue;
//fprintf(stderr,"P2: %s\n",str);
printf("%s\n",str);
//write(STDOUT_FILENO,str,sizeof(str));
}
}
}
client.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/select.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
int main(int argc, char *argv[])
{
if(argc != 2){
printf("\nError: %s required argument [Fifo Name]\n\n",argv[0]);
exit(EXIT_FAILURE);
}
int fd,wr,rd,ret;
fd_set readset;
fd = open(argv[1],O_RDWR);
if(fd==-1){
perror("Error Failed to open fifo\n");
exit(EXIT_FAILURE);
}
while(!0){
FD_ZERO(&readset);
FD_SET(fd,&readset);
FD_SET(STDIN_FILENO,&readset);
sleep(2);
ret = select(fd+1,&readset,NULL,NULL,NULL);
if(ret==-1){
perror("Error select() ");
exit(EXIT_FAILURE);
}
char str[512]="";
if(FD_ISSET(fd,&readset)){
rd = read(fd,str,sizeof(str));
if(rd==-1){
perror("Error while reading from fifo");
exit(EXIT_FAILURE);
}else if(rd==0)
continue;
//fprintf(stderr,"P2: %s\n",str);
printf("%s\n",str);
//write(STDOUT_FILENO,str,sizeof(str));
}
if(FD_ISSET(STDIN_FILENO,&readset)){
//fprintf(stderr, ">> ");
rd = read(STDIN_FILENO,str,sizeof(str));
if(rd==-1){
perror("Error while reading from fifo");
exit(EXIT_FAILURE);
}
char temp[512]="Client :: ";
strcat(temp,str);
wr = write(fd,temp,sizeof(temp));
if(wr==-1){
perror("Error while writing to fifo ");
exit(EXIT_FAILURE);
}
continue;
}
}
}
and the output is :
I am trying to write a C program which uses standard I/O and System calls to perform copying of contents of one file to another file.
So far, I have done this :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd1, fd2;
char buffer[1024];
long int n1;
if(((fd1 = open(argv[1], O_RDONLY)) == -1) || ((fd2=open(argv[2],O_CREAT|O_WRONLY|O_TRUNC, 0700)) == -1)){
perror("file problem");
exit(1);
}
while((n1=read(fd1, buffer, 1024) > 0)){
if(write(fd2, buffer, n1) != n1){
perror("writing problem ");
exit(3);
}
}
close(fd1);
close(fd2);
}
When I run the program like this :
cc copyContents.c
./a.out one.txt two.txt
Assuming that one.txt is well defined, what I want is to create a new file called two.txt and copy over all the contents of one.txt
When I look into the contents of two.txt after running the program, it has literally nothing in it. Just a blank file.
Where am I going wrong?
You wrote
while((n1=read(fd1, buffer, 1024) > 0)){
instead of
while ( (n1 = read(fd1, buffer, 1024)) > 0)
In your code the code int the while condition boils down to:
n1 = (read(fd1, buffer, 1024) > 0)
So the read is done correctly, it's return value is compared to 0, the result of the comparision (0 or 1) is assigned to n1.
This shows once more how important it is to format your code in a way that makes it readable.
You could have debugged this easily yourself with a debugger or by inserting one or two printfs in your code.
Input:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
void typefile (char *filename)
{
int fd, nread;
char buf[1024];
fd = open (filename, O_RDONLY);
if (fd == -1) {
perror (filename);
return;
}
while ((nread = read (fd, buf, sizeof (buf))) > 0)
write (1, buf, nread);
close (fd);
}
int main (int argc, char **argv)
{
int argno;
for (argno = 1; argno < argc; argno )
typefile (argv[argno]);
exit (0);
}
Output:
student#ubuntu:~$gcc –o prg10.out prg10.c
student#ubuntu:~$cat > ff
hello`enter code here`
hai
student#ubuntu:~$./prg10.out ff
hello
hai
This is the best solution and easily executable.
input:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int f1, f2;
char buff[50];
long int n;
if(((f1 = open(argv[1], O_RDONLY)) == -1 || ((f2=open(argv[2], O_CREAT |
O_WRONLY | O_TRUNC, 0700))== 1)))
{
perror("problem in file");
exit(1);
}
while((n=read(f1, buff, 50))>0)
if(write(f2, buff, n)!=n)
{
perror("problem in writing");
exit(3);
}
if(n==-1)
{
perror("problem in reading");
exit(2);
}
close(f2);
exit(0);
}
Output:
cc sys.c
./a.out a.txt b.txt
cat b.txt
So, a.txt should have some content and this content is copied to b.txt
by "cat b.txt" you can cross-check the content(which is in "a.txt").
Narenda checks if n==-1 inside the loop, but, the loop test is n>0, so, that'll never happen.
Also, the test for a bad read should precede the attempt to write.
I'm writing a simple application which will use anonymous pipes to communicate with child process called using execl().
Child process is simple echo application.
I want to redirect stdin and stdout to pipes and use them to receive data sent by child in parent.
Now only two lines are echoed.
Any ideas what is wrong?
Here is my code:
(parent.c)
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <errno.h>
int main()
{
int parent_to_child[2];
int child_to_parent[2];
if(pipe(parent_to_child) == -1) exit(-1);
if(pipe(child_to_parent) == -1) exit(-1);
switch(fork())
{
case -1: exit(-1);
case 0: //child
if(close(0) == -1) exit(-1);
if(dup(parent_to_child[0]) != 0) exit(-1);
fprintf(stderr, "stdin changed\n");
if(close(1) == -1) exit(-1);
if(dup(child_to_parent[1]) != 1) exit(-1);
fprintf(stderr, "stdout changed\n");
close(parent_to_child[0]);
close(parent_to_child[1]);
close(child_to_parent[0]);
close(child_to_parent[1]);
execl("./child_process","child_process", (char*)NULL);
exit(-1);
default: //parent
close(parent_to_child[0]);
close(child_to_parent[1]);
size_t size = 1024;
char* line = (char *) malloc(size);
while(getline(&line, &size, stdin) != -1)
{
if(write(parent_to_child[1], line, (strlen(line)+1)*sizeof(char)) == -1)
{
printf("%d", errno);
exit(-1);
}
read(child_to_parent[0], line, size);
printf("%s", line);
}
}
return 0;
}
(child_process.c)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
size_t size = 1024;
char* line = (char*) malloc(size);
setlinebuf(stdout);
setlinebuf(stdin);
fprintf(stderr, "child started\n");
while(getline(&line, &size, stdin) != -1)
{
printf("%s", line);
}
fprintf(stderr, "exiting");
free(line);
return 0;
}
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#define BUFSZ 2048
int main()
{
int shmid,i,fd,nwrite,nread;
char *shmadd;
char buf[5];
buf[5] = '\0';
if((shmid=shmget(IPC_PRIVATE,BUFSZ,0x666))<0)
{
perror("shmget");
exit(1);
}
else
printf("created shared-memory: %d\n",shmid);
if((shmadd=shmat(shmid,0,0))<(char *)0)
{
perror("shmat");
exit(1);
}
else
printf("attached shared-memory\n");
shmadd="Hello";
if((fd = open("share",O_CREAT | O_RDWR,0666))<0)
{
perror("open");
exit(1);
}
else
printf("open success!\n");
if((nwrite=write(fd,shmadd,5))<0)
{
perror("write");
exit(1);
}
else
printf("write success!\n");
lseek( fd, 0, SEEK_SET );
if((nread=read(fd,buf,5))<0)
{
perror("read");
exit(1);
}
else
printf("read %d form file:%s\n",nread,buf);
if(close(fd) == -1)
printf("close fd fails!\n");
else
printf("close fd succeeds!\n");
if((shmdt(shmadd))<0)
{
perror("shmdt");
exit(1);
}
else
printf("deleted shared-memory\n");
exit(0);
}
Above is the code which is to demo the shared memory in Linux. And the running result is below:
$ ./ex2
created shared-memory: 1572887
attached shared-memory
open success!
write success!
read 5 form file:Hello
close fd succeeds!
shmdt: Invalid argument
As you can see, everything goes fine except shmdt(). Why it fails?
Further:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#define BUFSZ 2048
int main()
{
int shmid,i,fd,nwrite,nread;
char *shmadd;
char buf[5];
buf[5] = '\0';
if((shmid=shmget(IPC_PRIVATE,BUFSZ,0x666)) < 0)
{
perror("shmget");
exit(1);
}
else
printf("created shared-memory: %d\n",shmid);
if((shmadd=shmat(shmid,0,0)) < (char *)0)
{
perror("shmat");
exit(1);
}
else
printf("attached shared-memory\n");
strcpy(shmadd, "Hello");
if((fd = open("share",O_CREAT | O_RDWR,0666)) < 0)
{
perror("open");
exit(1);
}
else
printf("open success!\n");
if((nwrite=write(fd,shmadd,5)) < 0)
{
perror("write");
exit(1);
}
else
printf("write success!\n");
lseek( fd, 0, SEEK_SET );
if((nread=read(fd,buf,5)) < 0)
{
perror("read");
exit(1);
}
else
printf("read %d form file:%s\n",nread,buf);
if(close(fd) == -1)
printf("close fd fails!\n");
else
printf("close fd succeeds!\n");
if((shmdt(shmadd))<0)
{
perror("shmdt");
exit(1);
}
else
printf("deleted shared-memory\n");
exit(0);
}
Following your answers, I changed the code as above. But now I got new error!
$ ./ex2
created shared-memory: 2129948
attached shared-memory
Segmentation fault (core dumped)
I seems that strcpy causes the error. But why?
This is the problem:
shmadd="Hello";
This changes the shmadd pointer to point to a string in memory. I think you intended to copy the string into the shared memory. To do that, you would do:
strcpy(shmadd,"Hello");
Also note that your check for errors is wrong, it should be:
if((shmadd=shmat(shmid,0,0)) == (void *)-1) { ... error ... }
And your permissions should be octal, not hex:
if((shmid=shmget(IPC_PRIVATE,BUFSZ,0666)) < 0)
Your check for an error with shmadd in this line is incorrect:
if((shmadd=shmat(shmid,0,0)) < (char *)0)
You need to do an explicit comparison to -1 as per the man page, as a -1 cast to a pointer becomes an unsigned value (0xFFFFFFFF on 32-bit systems). Replace that line with this one:
if((shmadd=shmat(shmid,0,0)) == (char *)-1)
and you'll get a permission denied error because you are not root.
I'm writing a coprocess program using pipe. It works fine when the child read some data, handle it and output it. But when I read all the data and handle it, it just pending. Any body have some idea? Thank you.
Here is the source code:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
int main()
{
#define MAXSIZE 1024
char workload[MAXSIZE];
char result[MAXSIZE];
workload[strlen(workload)] = EOF;
int workload_size = strlen(workload);
int fd1[2], fd2[2];
int n;
pid_t pid;
if (pipe(fd1) < 0 || pipe(fd2) < 0) {
fprintf(stderr, "pipe error: %s\n", strerror(errno));
exit(1);
}
if ((pid = fork()) < 0) {
fprintf(stderr, "fork error: %s\n", strerror(errno));
exit(1);
} else if (pid > 0) {
close(fd1[0]);
close(fd2[1]);
while(fgets(workload, MAXSIZE, stdin) != NULL)
{
workload_size = strlen(workload);
if (write(fd1[1], workload, workload_size) != workload_size) {
fprintf(stderr, "write to pipe error: %s\n", strerror(errno));
exit(1);
}
if ((n = read(fd2[0], result, MAXSIZE)) < 0) {
fprintf(stderr, "read from pipe error: %s\n", strerror(errno));
exit(1);
}
if (n == 0) {
fprintf(stderr, "child closed the pipe\n");
exit(1);
}
result[n] = 0;
if (puts(result) == EOF) {
fprintf(stderr, "fputs error\n");
exit(1);
}
}
} else {
close(fd1[1]);
close(fd2[0]);
if (fd1[0] != STDIN_FILENO) {
if (dup2(fd1[0] ,STDIN_FILENO) != STDIN_FILENO) {
fprintf(stderr, "dup2 error to stdin.\n");
exit(1);
}
close(fd1[0]);
}
if (fd2[1] != STDOUT_FILENO) {
if (dup2(fd2[1] ,STDOUT_FILENO) != STDOUT_FILENO) {
fprintf(stderr, "dup2 error to stdout.\n");
exit(1);
}
close(fd2[1]);
}
if (execl("./a.out", "a.out", NULL) < 0) {
fprintf(stderr, "execl error: %s\n", strerror(errno));
exit(1);
}
exit(0);
}
return 0;
}
Here is the source code of a.out, it works well with this:
#include <stdio.h>
#include <string.h>
int main()
{
#define MAXSIZE 1024
char x[MAXSIZE];
int n;
while(scanf("%s", x) != EOF)
{
printf("len:%d %s", strlen(x), x);
fflush(stdout);
}
return 0;
}
But it seems just pending when I write the code like this:
#include <stdio.h>
#include <string.h>
int main()
{
#define MAXSIZE 1024
char x[MAXSIZE];
int n;
while(scanf("%s", x) != EOF);
printf("Ok\n");
fflush(stdout);
return 0;
}
The way you are calling scanf with %s may overflow the x buffer. You should at least modify the scanf with a width modifier.
#include <stdio.h>
#include <string.h>
int main()
{
#define MAXSIZE 1024
char x[MAXSIZE];
int n;
while(scanf("%1024s", x) != EOF)
{
printf("len:%d %s", strlen(x), x);
fflush(stdout);
}
return 0;
}
And similarly for your other program.
The reason your program is getting blocked is because your second a.out program is looped doing another scanf, when at the same time the parent program is trying to read a response back into result.
You should test and loop while not feof and you might use popen & pclose
You probably want to use some multiplexing system call like poll