Passing struct through socket via recv C/C++

7.8k Views Asked by At

Helo, i am trying to pass it like this

typedef struct t_timeSliceRequest{
unsigned int processId;
unsigned int timeRequired;
int priority;
}timeSliceRequest;

struct t_timeSliceRequest request = { 1,2,1 };
sendFlag = send(socketID,(timeSliceRequest *) &request, sin_size ,0);

and on server side

recvFlag = recv(socketID,(timeSliceRequest *) &request,sin_size,0);

but its receiving garbage, even recv returning -1, please help

This is my full Conde

#include<sys/socket.h>
#include<sys/types.h>
#include<string.h>
#include<stdio.h>
#include<arpa/inet.h>
#include<time.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>

enum priority_e{ high, normal, low };

typedef struct t_timeSliceRequest{
    unsigned int processId;
    unsigned int timeRequired;
    int priority;
}timeSliceRequest;

typedef struct t_TimeSliceResponse {
    timeSliceRequest original_req;

    // Unix time stamp of when process was started on server
    unsigned int time_started;

    // Waiting and running time till end of CPU bust
    unsigned int ttl;

} TimeSliceResponse;


int main(int argc, char ** argv){
    int socketID = 0, clientID = 0;
    char sendBuffer[1024], recvBuffer[1024];
    time_t time;
    struct sockaddr_in servAddr, clientAddr;
    struct t_timeSliceRequest request = {1,1,0};

memset(sendBuffer, '0', sizeof(sendBuffer));
memset(recvBuffer, '0', sizeof(recvBuffer));

fprintf(stdout,"\n\n --- Server starting up --- \n\n");
fflush(stdout);

socketID = socket(AF_INET, SOCK_STREAM, 0);
if(socketID == -1){
    fprintf(stderr, " Can't create Socket");
    fflush(stdout);
}

servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(5000);
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);

int bindID, sin_size, recvFlag;
bindID = bind(socketID, (struct sockaddr *)&servAddr, sizeof(servAddr)); // Casting sockaddr_in on sockaddr and binding it with socket id
if(bindID!=-1){
    fprintf(stdout," Bind SucessFull");
    fflush(stdout);
    listen(socketID,5);
    fprintf(stdout, " Server Waiting for connections\n");
    fflush(stdout);
    while(1){
        sin_size = sizeof(struct sockaddr_in);
        clientID = accept(socketID, (struct sockaddr *) &clientAddr, &sin_size);
        fprintf(stdout,"\n I got a connection from (%s , %d)", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
        fflush(stdout);
        sin_size = sizeof(request);
        recvFlag = recv(socketID, &request,sin_size,0);
        perror("\n Err: ");
        fprintf(stdout, "\n recvFlag: %d", recvFlag);
        fprintf(stdout, "\n Time Slice request received:\n\tPid: %d \n\tTime Required: %d ", ntohs(request.processId), ntohs(request.timeRequired));
        fflush(stdout);
        snprintf(sendBuffer, sizeof(sendBuffer), "%.24s\n", ctime(&time));
        write(clientID, sendBuffer, strlen(sendBuffer));
        close(clientID);
        sleep(1);
    }
}else{
    fprintf(stdout, " Unable to Bind");
}
close(socketID);
return 0;
}

And Client Code is:

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>

enum priority_e{ high = +1, normal = 0, low = -1};

typedef struct t_timeSliceRequest{
    unsigned int processId;
    unsigned int timeRequired;
    int priority;
}timeSliceRequest;

int main(int argc, char *argv[])
{
    int socketID = 0 /*Socket Descriptor*/, n = 0;
    char recvBuffer[1024];
    memset(recvBuffer, '0',sizeof(recvBuffer));
    struct sockaddr_in servAddr;

    struct t_timeSliceRequest request = { 1,2,high };

    if(argc!=2){
        fprintf(stderr,"\n Usage: %s <ip of server> \n",argv[0]);
        return 1;
    }

    socketID = socket(AF_INET, SOCK_STREAM, 0);
    if(socketID == -1){
        fprintf(stderr, "\n Can't create socket \n");
        return 1;
    }

    servAddr.sin_family = AF_INET;
    servAddr.sin_port = htons(5000);

    if(inet_pton(AF_INET, argv[1], &servAddr.sin_addr)==-1){
        fprintf(stderr, "\n Unable to convert given IP to Network Form \n inet_pton Error");
        return 1;
    }

    int connectFlag, sendFlag = 0;
    connectFlag = connect(socketID, (struct sockaddr *)&servAddr, sizeof(servAddr));
    if(connectFlag == -1){
       fprintf(stderr, " Connection Failed\n");
       return 1;
    }

    int sin_size = sizeof(struct t_timeSliceRequest);
    fprintf(stdout, " \n %d \n %d \n %d", request.processId, request.timeRequired, request.priority);
    sendFlag = send(socketID, &request, sin_size ,0);
    fprintf(stdout, "\nSend Flag: %d\n", sendFlag);

    n = read(socketID, recvBuffer, sizeof(recvBuffer)-1);
    recvBuffer[n] = 0;
    fprintf(stdout, "%s",recvBuffer);
    if(n < 0){
        fprintf(stderr, " Read error\n");
    }
    return 0;
}

This is the full Code, its giving 'Transport endpoint is not connected'

2

There are 2 best solutions below

1
On BEST ANSWER

Transport endpoint is not connected error is returned when your socket isn't bound to any (port,address) pair.

If it's a server side, you should use the socket descriptor that is returned by accept call. In case of a client - you should use a socket that is returned by the successful call to connect.

Btw, sending structure the way you are is quite dangerous. Compilers might insert padding bytes between structure members (invisible to you program, but they take space in the structure) to conform some alignment rules for the target platform. Besides, different platforms might have different endianness, which might screw your structure completely. If your client and server are compiled for different machines, the structure layout and endianness can be incompatible. To solve this problem, you can use packed structures. A way of declaring a structure as packed depends on a compiler. For GCC this can be done by means of adding a special attribute to a structure.

Another way to solve this problem is to put each individual field of a structure to a raw byte-buffer manually. The receiving side should take all this data out in exactly the same way as the data was originally put into that buffer. This approach can be tricky, since you need to take into account a network byte order when saving multi-byte values (like int, long etc). There is a special set of functions like htonl, htons, ntohs etc for that.

Updated

In your server:

recvFlag = recv(socketID, &request,sin_size,0);

Here it should be

recvFlag = recv(clientID, &request,sin_size,0);

socketID is a passive socket and can only accept connections (not send any data).

What is more, the result of accept isn't checked for -1.

1
On

Keep in mind that sending structs like this over the network may lead to interoperability problems:

  1. if source and destination have different endianess, you're going to receive wrong data (consider using functions like htonl to convert the data to network endianess)
  2. you struct needs to be packed, otherwise different compilers can align differently the variables of the struct (see this to get an idea about aligning the variables)

In any case, ENOTCONN suggests an error establishing the connection between the two hosts.