Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sending buffer length and buffer over socket in c

Tags:

c

sockets

I'm trying to send a string to a server application using C, but I've hit a snag. I'm fairly new to network programming, and I think my code is barking up the wrong tree.

The message is supposed to be message length + message and is unpacked on the other side by a python server as such (buf being the raw incoming data):

msg_len_bytes = buf[0:4]
msg_len = struct.unpack("!L", msg_len_bytes)[0]

! means network byte order and L means unsigned long.

It is fairly simple to send a regular string. send(sock, message, strlen(message), 0);

But adding the message length I can't quite get a handle on. Here is the code for my client thus far:

struct msgstruct {
        uint32_t length;
        char send_data[4096];
};

int main()

{
    int sock;
    struct msgstruct message;
    char data[4096] = "<MOP><test/></MOP>";

    for ( int i = 0; i < strlen(data); i++ ) {
      message.send_data[i] = data[1];
    }

    struct hostent *host;
    struct sockaddr_in server_addr;

    unsigned long buflen = sizeof(message.send_data);
    uint32_t bufsend = htonl(buflen);

    message.length = bufsend;

    host = gethostbyname("127.0.0.1");

    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        perror("Socket");
        exit(1);
    }

    server_addr.sin_family = AF_INET;     
    server_addr.sin_port = htons(12998);   
    server_addr.sin_addr = *((struct in_addr *)host->h_addr);
    bzero(&(server_addr.sin_zero),8); 


    if (connect(sock, (struct sockaddr *)&server_addr,
                sizeof(struct sockaddr)) == -1) {
        perror("Connect");
        exit(1);
    }

    if(send(sock, message.length + message.send_data, sizeof(message), 0) == -1){
        printf("\nSocket error.");
        exit(1);
    }
    return 0;
}

I've tried a few variations, but I always end up with a socket error. Is it because I'm mixing types in the second arguement for send? I get compilation errors if I try to send the struct.


1 Answers

You can use 2 subsequent sends:

send(sock, &message.length, sizeof(message.length), 0);
send(sock, message.send_data, message.length*sizeof(char), 0);

Or better prepare buffer with first 4 bytes as message length:

char buff[MAX_BUFF] = "";
int  len_disp = sizeof(message.length);
memcpy(buff, &message.length, len_disp);
memcpy(&buff[len_disp], &message.length, message.length*sizeof(char));
send(sock, buff, message.length*sizeof(char) + len_disp, 0);

EDIT: For small messages comment -- disabling Nagle's algorithm.

BOOL bNagleEnabled = FALSE;
if(setsockopt(sAccept, IPPROTO_TCP, TCP_NODELAY, (char *)&bNagleEnabled, sizeof(BOOL)))
{
  ReportError("Setting TCP_NODELAY socket option failed");
  return -2;
}
like image 107
Mikhail Churbanov Avatar answered Nov 25 '25 11:11

Mikhail Churbanov