C language, using structs to send data from client to server - c

I have to create a client and server, where the client will send a character and an integer (using structs) and then my client will iterate the letter by n (integer) times and will send it back to the client.
For instance: a and 4 are sent from the client, server will manipulate and send a string of 4 a's (aaaa) back to the client.
I know I am really close to get the code but once I send my char and int, I get a "segmentation fault (core dumped) error". I have done my research and the error shows up due to a missing cast, memory being accessed where is not supposed to access, or that a pointer might be null.
The code is as follow:
Client:
// ClientTest.c
// opens fifo1 for writing and fifo2 for reading
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
struct problem {
char letter[1];
int number[1];
};
main (void)
{
struct problem x=0; //Initializing structure to null
int fda; // to write to character server
int fdb; // to read response from character server
int i; // for the iteration
printf("Client: Please enter a character: ");
scanf("%c", &x.letter[0]);
printf("Client: Please enter an integer: ");
scanf("%d", &x.number[0]);
memset(&x.letter, 0, 1);
memset(&x.number, 0, 1);
if((fda=open("FIFO1", O_WRONLY))<0)//opening and validating fifos
printf("cant open fifo to write");
if((fdb=open("FIFO2", O_RDONLY))<0)
printf("cant open fifo to read");
write(fda, x.number, 1);
printf("\nClient: Got the integer sent, now waiting for response ");
//sleep(0.250);
write(fda, x.letter, 1);
printf("\nClient: Got the character sent, now waiting for response ");
char outletter[7];
read(fdb, outletter, 7);
printf("\nClient: received characters from server %c", outletter);
close(fda);
close(fdb);
printf ("\nall done!\n");
}
server
// ServerTest.c
// makes 2 fifos named fifo1 and fifo2
// opens fifo1 for reading and fifo2 for writing
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
struct problem {
char letter[1]; // struct to store the character
int number [1]; // struct to store the integer
};
main (void)
{
struct problem x;
int fda; // to read from client char
int fdb; // to write to client char
int finish; // lets me know that client is done
int i; // because C needs this defined as int
int p;
char outletter[7];
memset(&x.letter, 0, 7);
memset(&x.number, 0, 1);
/* Create the fifos and open them */
if ((mkfifo("FIFO1",0666)<0 && errno != EEXIST))
{
perror("cant create FIFO1");
exit(-1);
}
if ((mkfifo("FIFO2",0666)<0 && errno != EEXIST))
{
perror("cant create FIFO2");
exit(-1);
}
if((fda=open("FIFO1", O_RDONLY))<0)
printf("cant open fifo to write");
if((fdb=open("FIFO2", O_WRONLY))<0)
printf("cant open fifo to read");
read(fda, x.letter, 1); //read the character
read(fda, x.number, 1); //read the integer
printf("\nServer: just got character: , %c", x.letter[0]);
printf("\nServer: just got integer: , %d", x.number[0]);
p=x.number[0]-'0';
for( i = 0; i<=p; i++) // iteration to create the character's string
outletter[p] = x.letter[0];
printf("iteration: %d and character: %c\n", i, outletter[0]); // validating the character and integer received
printf("\nServer: outchar is, %s", outletter); // this shows the character to be sent back to client
write(fdb, outletter, p);
printf("\nServer: Got the characters sent: %s", outletter ); // this sends the letter back to client
if(finish == 1)
printf("\nServer: This says I am ready to close ");
close(fda);
close(fdb);
unlink("FIFO1");
unlink("FIFO2");
}

There are many problems with your code, I've made it running but you can still improve it.
Client:
// ClientTest.c
// opens fifo1 for writing and fifo2 for reading
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
struct problem {
char letter[1];
int number[1];
};
main (void)
{
struct problem x;
int fda; // to write to character server
int fdb; // to read response from character server
int i; // for the iteration
memset(&x, 0, sizeof(struct problem)) ;
printf("Client: Please enter a character: ");
scanf("%c", x.letter);
printf("Client: Please enter an integer: ");
scanf("%d", x.number);
// removed or else the letter and number would be reverted to zero
// memset(&x.letter, 0, sizeof(char));
// memset(&x.number, 0, sizeof(int));
if((fda=open("FIFO1", O_WRONLY))<0)//opening and validating fifos
printf("cant open fifo to write");
if((fdb=open("FIFO2", O_RDONLY))<0)
printf("cant open fifo to read");
write(fda, x.letter, sizeof(char));
printf("\nClient: Got the character sent, now waiting for response ");
write(fda, x.number, sizeof(int));
printf("\nClient: Got the integer sent, now waiting for response ");
//sleep(0.250);
char outletter[7];
read(fdb, outletter, 7);
printf("\nClient: received characters from server:") ;
printf("%s\n", outletter);
close(fda);
close(fdb);
printf ("\nall done!\n");
}
Server:
// ServerTest.c
// makes 2 fifos named fifo1 and fifo2
// opens fifo1 for reading and fifo2 for writing
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
struct problem {
char letter[1]; // struct to store the character
int number[1]; // struct to store the integer
};
main (void)
{
struct problem x;
int fda; // to read from client char
int fdb; // to write to client char
int finish; // lets me know that client is done
int i; // because C needs this defined as int
int p;
char outletter[7];
memset(x.letter, 0, sizeof(char));
memset(x.number, 0, sizeof(int));
/* Create the fifos and open them */
if ((mkfifo("FIFO1",0666)<0 && errno != EEXIST))
{
perror("cant create FIFO1");
exit(-1);
}
if ((mkfifo("FIFO2",0666)<0 && errno != EEXIST))
{
perror("cant create FIFO2");
exit(-1);
}
if((fda=open("FIFO1", O_RDONLY))<0)
printf("cant open fifo to write");
if((fdb=open("FIFO2", O_WRONLY))<0)
printf("cant open fifo to read");
read(fda, x.letter, sizeof(char)); //read the character
read(fda, x.number, sizeof(int)); //read the integer
printf("\nServer: just got character: , %c", x.letter[0]);
printf("\nServer: just got integer: , %d", x.number[0]);
p=x.number[0];
if (p > 6) p = 6; // Cannot write more than 6 characters in outletter
for( i = 0; i<=p; i++) { // iteration to create the character's string
outletter[i] = x.letter[0];
printf("iteration: %d and character: %c\n", i, outletter[i]); // validating the character and integer received
}
outletter[p] = '\0'; // the string must finish with '\0'
printf("\nServer: outchar is, %s", outletter); // this shows the character to be sent back to client
write(fdb, outletter, p);
printf("\nServer: Got the characters sent: %s", outletter ); // this sends the letter back to client
if(finish == 1)
printf("\nServer: This says I am ready to close ");
close(fda);
close(fdb);
unlink("FIFO1");
unlink("FIFO2");
}

Related

Use read() to get the name of a file from a pipe and open() it in c

This is all done on a linux machine.
I have a pipe, fp, sending from the parent to the child the name of a file using a buffer.
The buffer is:
char buf[20];
the child has the following code:
{
//we are in the child
close(fp[1]);
int fd;
read(fp[0],buf,20);
if((fd=(open(buf, O_RDONLY)))==-1) exit(1);
else exit(0);
close(fp[0]);
}
Even if I type in the name of a file that exists, I'm getting the exit status of 1. So...
this unfortunately doesn't work. The issue is that the buff itself not only does '\n', but also also plenty of '\0', all of which don't actually exist in the name of real file. I've tried replacing the '\n' with a '\0' but that also doesn't work. How can I solve this?
Here's the whole code.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
int main(){
int fp[2];
if (pipe(fp) < 0){
printf("error creating pipe\n");
exit(-1);
}
int id;
char buf[20];
id=fork();
//father process here --------------------------------
if (id!=0){
close(fp[0]); //closing read
printf("program name: ");
fflush(stdout);
read(STDIN_FILENO,buf,20);
write(fp[1],buf,20);
int waitstatus, exitcode;
wait(&waitstatus);
//check if exited correctly
if (WIFEXITED(waitstatus))
exitcode = WEXITSTATUS(waitstatus);
else
{
printf("Bad exit\n");
return 0;
}
if (exitcode==1) printf("error, file doesn't exist\n");
else printf("file does exist\n");
close(fp[1]);
}
//child process here --------------------
else{
close(fp[1]); //closing write
int fd;
read(fp[0],buf,20);
//write(STDOUT_FILENO, buf, 20);
if((fd=(open(buf, O_RDONLY)))==-1) exit(1);
exit(0);
close(fp[0]);
}
}
You send the full buf which contains a newline and other indeterminate values. You need to remove the newline and I suggest that you only send what you need on the receiving end.
printf("program name: ");
fflush(stdout);
if(fgets(buf, sizeof buf, stdin)==NULL) return 1;
size_t len = strlen(buf);
buf[len - 1] = '\0'; // remove the newline
write(fp[1], buf, len); // only send what you actually need

Sending a process id from client to server

My task is to write a client program that writes a struct with a privateFIFO name (FIFO_XXXX, where XXXX is the pid that we get from the getpid( ) function) to the server. Then, have the server read the privateFIFO name and write a message back to the client. i.e., Read the message and print it on the client side. I am having trouble sending the FIFO_XXXX to the server program and also writing a message from the server back to client.
client code:
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main (void)
{
struct values
{
char privateFIFO[14];
int intbuff;
}input;
int fda; // common FIFO to read to write to server
int fdb; // Private FIFO to read from server
int clientID;
int retbuff;
char temp[14];
clientID = getpid();
strcpy(input.privateFIFO, "FIFO_");
sprintf(temp, "%d", clientID);
strcat(input.privateFIFO, temp);
printf("\nFIFO name is %s", input.privateFIFO);
// Open common FIFO to write to server
if((fda=open("FIFO_to_server", O_WRONLY))<0)
printf("cant open fifo to write");
write(fda, &input, sizeof(input)); // write the struct to the server
close(fda);
// Open private FIFO to read
if((fdb=open(input.privateFIFO, O_RDONLY))<0)
read(fdb, &retbuff, sizeof(retbuff));
printf("\nAll done!\n");
close(fdb);
}
server code:
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
struct values
{
char privateFIFO[14];
int intbuff;
}input;
int main (void)
{
int fda; //common FIFO to read from client
int fdb; //private FIFO to write to client
int retbuff;
int output;
// create the common FIFO
if ((mkfifo("FIFO_to_server",0666)<0 && errno != EEXIST))
{
perror("cant create FIFO_to_server");
exit(-1);
}
// open the common FIFO
if((fda=open("FIFO_to_server", O_RDONLY))<0)
printf("cant open fifo to write");
output = read(fda, &input, sizeof(input));
// create the private FIFO
if ((mkfifo(input.privateFIFO, 0666)<0 && errno != EEXIST))
{
perror("cant create privateFIFO_to_server");
exit(-1);
}
printf("Private FIFO received from the client and sent back from server is: %d", output);
//open private FIFO to write to client
if((fdb=open(input.privateFIFO, O_WRONLY))<0)
printf("cant open fifo to read");
write(fdb, &retbuff, sizeof(retbuff));
close(fda);
unlink("FIFO_to_server");
close(fdb);
unlink(input.privateFIFO);
}
Use IPC message Queues. It better and simple. Indeed, This mechanism manages synchronization between read and write operations, concurrent access, ...:
The Writer Process:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
// structure for message queue
struct mesg_buffer {
long mesg_type;
char mesg_text[100];
} message;
int main()
{
key_t QueueKey;
int msgid;
// ftok : generate a unique OPC key
QueueKey = ftok("FIFO_XXXX", 65);
// msgget creates a message queue and returns identifier
msgid = msgget(QueueKey, 0666 | IPC_CREAT);
// Sending Data
message.mesg_type = 1;
printf("Write Data : ");
gets(message.mesg_text);
// msgsnd : Send message to the queue
msgsnd(msgid, &message, sizeof(message), 0);
// display the message
printf("Data send is : %s \n", message.mesg_text);
return 0;
}
The Reader Process:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
// structure for message queue
struct mesg_buffer {
long mesg_type;
char mesg_text[100];
} message;
int main()
{
key_t QueueKey;
int msgid;
// ftok to generate unique key
QueueKey = ftok("FIFO_XXXX", 65);
// msgget creates a message queue and returns identifier
msgid = msgget(QueueKey, 0666 | IPC_CREAT);
// msgrcv to receive message
msgrcv(msgid, &message, sizeof(message), 1, 0);
// display the message
printf("Data Received is : %s \n", message.mesg_text);
// IPC_RMID : destroy the message queue
msgctl(msgid, IPC_RMID, NULL);
return 0;
}
Remarque:
Be aware that a process can be both writer and reader. To do this, two message queues must be created for each process. the first allows for example to receive, the second to write. If you really want to separate read / write spaces for each process.

How to send line of text from server to client in C?

This program, on the server side, asks the user for an array size, array elements and an integer value to be searched in the array. If found it prints a message such as "The value 87 occurs at index position 4" and sends it back to client. I have managed to come up with the following code for server and client. However, how do I send the result of the search such as "The value 87 occurs at index position 4" back to server from client?
Client Code:
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#define MAX_SIZE 10 //maximum array size
int main (void)
{
int fda; // to write to server
int fdb; // to read response from server
struct{
int size;
int i;
int arr[MAX_SIZE];
} input;
if((fda=open("FIFO_to_server", O_WRONLY))<0)
printf("cant open fifo to write");
printf("Client: Please enter size of the array: ");
scanf("%d", &input.size);
printf("Enter the elements of the array: ");
for(i=0; i<size; i++)
{
scanf(%d", &arr[i]);
}
write(fda, &input, sizeof(input));
close(fda);
printf("\nClient: Got the array sent, now waiting for response ");
if((fdb=open("FIFO_to_client", O_RDONLY))<0)
printf("cant open fifo to read");
close(fdb);
printf ("\nall done!\n");
}
Server Code
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <sys/types.h>
int main (void)
{
int fda; // to read from client
int fdb; // to write
int i;
int toSearch;
int found;
int finish;
/* Create the fifos and open them */
if ((mkfifo("FIFO_to_server",0666)<0 && errno != EEXIST))
{
perror("cant create FIFO_to_server");
exit(-1);
}
if ((mkfifo("FIFO_to_client",0666)<0 && errno != EEXIST))
{
perror("cant create FIFO_to_client");
exit(-1);
}
if((fda=open("FIFO_to_server", O_RDONLY))<0)
printf("cant open fifo to write");
if((fdb=open("FIFO_to_client", O_WRONLY))<0)
printf("cant open file to read");
finish=read(fda, &input, sizeof(input));
printf("Server: just got the array: %d", arr);
printf("\Enter the integer to be searched in the array: ");
found = 0;
for(i=0; i<size; i++)
{
if(arr[i] == toSearch)
{
found = 1;
break;
}
}
if(found == 1)
{
printf("\n%d is found at position %d", toSearch, i + 1);
}
else
{
printf("\n%d is not found in the array", toSearch);
}
return 0;
close(fdb);
unlink("FIFO_to_client");
close(fda);
unlink("FIFO_to_server");
}

Need Help in Client and Server Programming in C

I am coding a small C program to test the client and server programs so that the client sends an integer to the client. The server multiplies the number by 10 and returns the integer*10 back to the client. When writing the integers to the FIFO, use sizeof(int) as the number of bytes in the 3rd parameter of the write( ) and read( ).
That is my code so far:
The Client task:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
main (void)
{
int fda; // to write to server
int fdb; // to read response from server
int number;
int outputnumber;
if((fda=open("FIFO_to_server", O_WRONLY))<0)
printf("cant open fifo to write");
if((fdb=open("FIFO_to_client", O_RDONLY))<0)
printf("cant open fifo to read");
printf("Client: Please enter an integer: ");
scanf("%d", &number);
write(fda, &number, sizeof(number));
printf("\nClient: Got the number sent, now waiting for response ");
read(fdb, &outputnumber, sizeof(outp utnumber));
printf("\nClient: received from server %s", outputnumber);
close(fda);
close(fdb);
printf ("\nall done!\n");
}
The server task:
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
main (void)
{
int fda; // to read from client
int fdb; // to write to client
int finish; // lets me know that client is done
int number;
int outputnumber;
/* Create the fifos and open them */
if ((mkfifo("FIFO_to_server",0666)<0 && errno != EEXIST))
{
perror("cant create FIFO_to_server");
exit(-1);
}
if ((mkfifo("FIFO_to_client",0666)<0 && errno != EEXIST))
{
perror("cant create FIFO_to_client");
exit(-1);
}
if((fda=open("FIFO_to_server", O_RDONLY))<0)
printf("cant open fifo to write");
if((fdb=open("FIFO_to_client", O_WRONLY))<0)
printf("cant open fifo to read");
finish=read(fda, number, sizeof(number)); //read the character
printf("Server: just got the number: ,%d", number));
outputnumber = 10*number;
write(fdb, outputnumber,sizeof(outputnumber));
printf("\nServer: Got the number sent");
if(finish == 1)
printf("\nServer: This says I am ready to close ");
close(fda);
close(fdb);
unlink("FIFO_to_server");
unlink("FIFO_to_client");
}
The Client's output show error:
-bash-3.2$ ./client
Client: Please enter an integer: 10
Client: Got the number sent, now waiting for response
Client: received from server ▒+▒▒▒▒▒▒7▒▒x}
all done!
The Server:
-bash-3.2$ ./server
Server: just got the number: 134614968
Server: Got the number sent-bash-3.2$

Why is this named pipe not printing the sent line?

The following server creates a named pipe when it's run like this:
./serverprogram -p nameofthepipe -t 99
the optarg after t indicates a number of threads to be created (not done here).
Anyway, the pipe isn't working here:
/* Open the first named pipe for reading */
int rdfd = open(pipeName, O_RDONLY);
/* Read from the first pipe */
int numread = read(rdfd, command_and_pid, 280);
printf("what's being read is %s \n", command_and_pid); // not printing!!1!
Why?
Server program:
#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>
int main (int argc, char * argv[])
{
char pipeName[30];
int numThreads;
char command_and_pid[280];
int opcion;
if (argc < 2) {
printf ("ERROR: Missing arguments\n");//
exit(1);
}
opterr = 0;
while ((opcion = getopt (argc, argv, "p:t:w")) != -1)
{
switch (opcion) {
case 'p': // -p indica el nombre del pipe
printf("The name of the pipe is: %s\n",optarg);
strcpy(pipeName, optarg);
break;
case 't'://-t indica los hilos
printf("The number of threads is: %s\n",optarg);
numThreads= atoi(optarg);
break;
case '?':
fprintf(stderr,"no reconozco esa opcion\n");
break;
}
}
int ret_val = mkfifo(pipeName, 0666);
if ((ret_val == -1) && (errno != EEXIST)) {
perror("Error creating the named pipe");
exit (0);
}
/* Open the first named pipe for reading */
int rdfd = open(pipeName, O_RDONLY);
/* Read from the first pipe */
int numread = read(rdfd, command_and_pid, 280);
printf("what's being read is %s \n", command_and_pid); // not printing!!1!
close(rdfd);
return 0;
}
Client program:
#include <unistd.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
int main (int argc, char * argv[])
{
char pipeName[30];
printf("write the name of the pipe used to write to the server \n");
fgets(pipeName,30, stdin);
/* Open the first named pipe for writing */
int wrfd = open(pipeName, O_WRONLY);
printf("write the name of the command you want to execute \n");
char command_and_pid[280];
char command[250];
fgets(command,250, stdin);
puts(command); //quitar
strcpy(command_and_pid,command);
strcat(command_and_pid," ");
int pipeIntId;
char pidstring [30];
int pid= getpid();
sprintf(pidstring,"%d", pid);
strcat(command_and_pid,pidstring);
int written;
written=write(pipeIntId,command_and_pid,280);
//write to the pipe
// send the command and pid
close(pipeIntId); // close write pipe
return 0;
}
In the client, fgets keeps the newline at the end of the line, so you'll need to strip that before opening the file.
Also, in the code as given, you're opening wrfd but writing to pipeIntId, which is uninitialized (though perhaps you are extracting something from a function here).

Resources