I am working on my school assignment which requires me to pass a structure that contains a char pointer from the client program to the server and print the structure data in the Server.c program. I am being able to pass the structure properly and being able to retrieve the integer data from the structure in server.c, but I am getting an error "Segmentation fault" when I try to print the char* data in the server.c program that is coming from the Client.c program. How do I fix it?
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<sys/socket.h>
#define PORT 8080
struct StudentInfo
{
char* name;
int roll;
}student;
int main()
{
student.name=(char*)malloc( 50 * sizeof(char));
student.name="Sara You";
student.roll=124;
int network_socket=socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(PORT);
serveraddr.sin_addr.s_addr=INADDR_ANY;
sendto(network_socket, &student, sizeof(student),0, (struct sockaddr*) &serveraddr, sizeof(serveraddr));
close(network_socket);
}
Server.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<string.h>
#define PORT 8080
struct StudentInfo
{
char* name;
int roll;
} student1;
int main()
{
student1.name=(char*)malloc( 50 * sizeof(char));
struct sockaddr_in serveraddr, cliaddr;
int network_socket=socket(AF_INET, SOCK_DGRAM, 0);
memset(&serveraddr,0,sizeof(serveraddr));
memset(&cliaddr,0,sizeof(cliaddr));
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(PORT);
serveraddr.sin_addr.s_addr=INADDR_ANY;
bind(network_socket, (struct sockaddr*) &serveraddr, sizeof(serveraddr));
int len=sizeof(cliaddr);
recvfrom(network_socket, &student1, sizeof(student1), 0, (struct sockaddr*) &cliaddr, &len);
printf("Name %s: ", student1.name); //Segmentation fault
printf("Name %d: ", student1.roll);
}
CodePudding user response:
It might be possible to fix this easily if you don't mind constraining student names to be less than, say, 100 bytes. It looks like you're sending the structure as a whole without any consideration for byte order. Therefore, if the byte order on the client and server match, then simply changing the structure definition will fix the problem. Of course, by making the memory for the name part of the structure, you don't have to allocate memory and you'll have to use strcpy
instead of the assignment of a pointer. Like so:
struct StudentInfo {
char name[100];
int roll;
} student;
int main (int argc, char *argv[]) {
//student.name=(char*)malloc( 50 * sizeof(char));
//student.name="Sara You";
strcpy(student.name, "Sara You"); // check length, truncate, or send multiple messages
UPDATE 1
If you must serialize what you send and deserialize what you receive, then you can use these two functions that return something that can be free
d:
char * serializeStudent (struct StudentInfo *stu) {
char *rval;
if (!stu || !stu->name) {
// errno = EINVAL;
return 0;
}
rval = malloc(strlen(stu->name) 21); // never cast malloc
if (!rval) {
return 0; // errno will be set by malloc
}
sprintf(rval, "dd%s", stu->roll, strlen(stu->name), stu->name);
return rval;
}
Call serializeStudent
before sending, send the string it returns (if it's not null), and then free
that string after the send is successful.
struct StudentInfo * deserializeSerializedStudent (char *ser) {
struct StudentInfo *rval;
if (!ser) {
// errno = EINVAL;
return 0;
}
rval = malloc(sizeof(*rval));
if (!rval) {
return 0; // errno will be set by malloc
}
int len;
int n = sscanf(ser, "dd", rval->roll, &len);
if (n != 2) {
// errno = EINVAL;
free(rval);
return 0;
}
rval->name = malloc(len 1);
if (!rval->name) {
free(rval);
return 0; // errno will be set by malloc
}
n = sscanf(ser 20, "%*s", len, rval->name);
if (n != 1) {
// errno = EINVAL;
free(rval);
return 0;
}
return rval;
}
Call deserializeSerializedStudent
after receiving a string that you know is complete. Then do what you need with the structure, then free it after freeing the string that it contains.