0

Curently I`m developing chat aplication using C and libevent library for both client and server. I started from simple prototype, where client simply send plain string, server recive it and send it to every connected user except the sender. But now I need to send not only the string, but also some information about the user, for example - his name. So, what the best wey to send complicated data (structs for exmaple) through sockets in C?

I have some code, that sends and recives structure as byte array, but i dont know, is it right to send it like that, or better to use JSON serialization for example. Thanks.

Client method, that read line and send it to server:

void *readmsg_and_send_msg(void *arg)
{
struct client *cl = (struct client *)arg;
struct sock_data data;
uint8_t sendbuff_array[DATA_BUFF_LENGTH];

data.type = SENDMSG_REQUEST;

char *line;

while (1)
{
    line = getline();

    if (line)
    {
        memcpy(data.data, (void *)line, strlen(line));
        memcpy(sendbuff_array, &data, sizeof(data));

        printf("%s\n", (char *)sendbuff_array);

        bufferevent_write(cl->buf_ev, (void *)sendbuff_array, sizeof(sendbuff_array));
    }
}
}

Server "on read" method:

void buffered_on_read(struct bufferevent *bev,
                  void *arg)
{
struct client *this_client = arg;
struct client *client;

sock_data_t *sockdata;

uint8_t data[DATA_BUFF_LENGTH];
size_t n;

/* Read 8k at a time and send it to all connected clients. */
for (;;)
{
    n = bufferevent_read(bev, &data, sizeof(data));

    //if 0 - end reading
    if (n <= 0)
        break;
}

sockdata = (sock_data_t *)data;

if (sockdata->type == SENDMSG_REQUEST)
{
    printf("\033[0;36mNew message %s from %d recived\033[0m\n", (char *)sockdata->data, this_client->fd);

    TAILQ_FOREACH(client, &client_tailq_head, entries)
    {
        if (client != this_client)
        {
            bufferevent_write(client->buf_ev, (void *)sockdata->data, sizeof(sockdata->data));
            printf("Message %s successfully sended to user %d\n", (char *)sockdata->data, client->fd);
        }
    }
}
else
{
    printf("%s  -  %d\n", (char *)sockdata->data, sockdata->type);
    printf("Unimplemented request type\n");
    return;
 }
 }

Struct, that I`m trying to send/recive:

#pragma pack(push, 1)
typedef struct sock_data_s
{
      request_type_e type;
      uint8_t data[DATA_BUFF_LENGTH];
} sock_data_t;
#pragma pack(pop)

Where request_type_e - enum, using for definding type on incoming request:

typedef enum request_type
{
    REG_REQUEST = 0x0, //registration request
    LOG_REQUEST,       // login request
    GETMSG_REQUEST,    // get list of room`s messages request
    SENDMSG_REQUEST,   // send message to room
} request_type_e;
  • `JSON` may have variable length data. Arrays for example. And that leads to encoding data size in a message. – user14063792468 Jan 16 '21 at 17:31
  • the posted code snippet does not compile! Please post a [mcve] so we can reproduce the problem and help you debug it. – user3629249 Jan 17 '21 at 18:52
  • regarding: `line = getline()` Here is the syntax for `getline()` *ssize_t getline(char **lineptr, size_t *n, FILE *stream);* Notice how the posted code fails to actually setup/use the function: `getline()` – user3629249 Jan 17 '21 at 18:57
  • strongly suggest to never use `json` – user3629249 Jan 17 '21 at 18:58
  • regarding *for (;;) { n = bufferevent_read(bev, &data, sizeof(data)); //if 0 - end reading if (n <= 0) break; }* This does not send any data anywhere. – user3629249 Jan 17 '21 at 19:00
  • a call to `write()` or `send()` does not (necessarily) send all the data in a single call. Therefore, that code should be in a loop, with a 'moving window' on the data. This loop should exit when all the data is sent. Use the accumulated returned value from the function call to track when all the data is sent – user3629249 Jan 17 '21 at 19:05
  • regarding: `n = bufferevent_read(bev, &data, sizeof(data));` if the function: `bufferevent_read()` actually uses the `read()` function, remember that a returned value of `0` actually means the sender has 'hung up'/closed the connection. also, this is always reading the data into the same location in the buffer. I.E. each successive pass through the loop overlays the data read on the prior pass through the loop – user3629249 Jan 17 '21 at 19:15
  • @user3629249 Why not to use JSON? As i know, casting structures to/from byte array might be different on different platforms. This getline is not the posix one, its just implementation of it. buferevent_read just reads data to buffer, its a libevent function. Sorry for long question, but i just want to know how to better send data through sockets :) – Mospan Kostya Jan 17 '21 at 22:00
  • @BorovKostyantin, it is very easy to make a coding error in JSON and it is completely unnecessary – user3629249 Jan 18 '21 at 02:35

0 Answers0