Messaging between C client and server


This example shows how to exchange messages between RimStone server and a C API client (see Client-API). The client uses FastCGI binary protocol to communicate with the server. SEMI messaging is used as a format of messages. In this example, a client sends 10 variable length message to the server (meaning each has a different number of key/value pairs); the server then gets each key/value and replies in kind. The client displays the result.

Note that status checking is not performed for simplicity here.
Create a server and start it
To get started, create a directory for this example and position in it:
mkdir -p msgapi
cd msgapi

Create file "srv.rim":
cat << 'EOF' > srv.rim
begin-handler /srv public
    silent-header

    request-body msg // get the message sent by client

    new-message m from msg // parse into key/value pairs 

    new-message r // create new reply message

    read-message m key k value v // read how many key/value pairs are there, that's
                                 // the how the client packed the data

    write-message r key "reply" value v // write into reply message how many key/value pairs
                                        // we're sending back

    start-loop repeat #v use i start-with 1
        read-message m key k value v // get key/value pair from client
        // write key/value pair to go back to the client
        write-message r key $i value "Reply is " + $i + " (from "+v+")"
    end-loop

    get-message r to rm // get the binary representation of the message
    print-out rm // send it back to client

end-handler
EOF

Create "msgapi" application ("-k"):
rim -k msgapi

Compile the server - this also demonstrates excluding directories from compilation (since RimStone will by default try to compile the RimStone and C code in all subdirectories). In this case, we're excluding subdirectory "c-api", which we will create in just a sec and place a C client program in it:
rim -q --exclude-dir=c-api

Start the server, with a single server process running:
mrim -w 1 msgapi

Create a client in C
Create directory for a C API client, and switch to it:
mkdir c-api
cd c-api

Next is the C code for your client. It sends a message to the server (comprised of key/value pairs), gets the reply back, and prints out key/value pairs in it. Create file "client.c" with this:
cat << 'EOF' > client.c
#include "rcli.h"

int rim_client (rim_cli *req, char *connection, char *method, char *app_path, char *request, char *url_params, char *body, int body_len);

// Send a request to RimStone server, see the example of use below
int rim_client (rim_cli *req, char *connection, char *method, char *app_path, char *request, char *url_params, char *body, int body_len)
{
    memset ((char*)req, 0, sizeof(rim_cli));
    req->server = connection;
    req->req_method = method;
    req->app_path = app_path;
    req->req = request;
    req->url_params = url_params;
    req->req_body = body;
    req->content_type = "application/rim";
    req->content_len = body_len;

    return rim_cli_request (req);
}

void main ()
{
    int i;
    // Get the path of Unix socket file to communicate with the server
    char dir[RIM_MAX_OS_UDIR_LEN];
    rim_dir (RIM_DIR_SOCKFILE, dir, sizeof(dir), "msgapi", NULL);

    // Make /srv request to msgapi application server 10 times
    for (i = 1; i < 10; i++)
    {
        rim_cli req; // Client C API request
        rim_msg *msg; // Message for client
        msg = rim_new_msg (NULL, 0); // Make a new message
        char key[100], value[100], count[100]; // alloc for message key/value pairs
        snprintf (count, sizeof(count), "%d", i); // the count (how many key/value pairs)
        rim_write_msg (msg, "count", count, strlen(count)); // write the count into the message
        int j;
        for (j = 1; j <= i; j++) // pack different number of key/value pairs, so for the first messasge
                                 // pack only one, for the second message pack 2 pairs, for the third message
                                 // pack 3 pairs etc. Just to make it interesting.
        {
            // write key/value into a message
            snprintf (key, sizeof(key), "%d", j);
            snprintf (value, sizeof(value), "message %d", j);
            rim_write_msg (msg, key, value, strlen(value));
        }
        // send message to RimStone server
        int res = rim_client (&req, dir, "POST", "/msgapi", "/srv", "/", rim_get_msg (msg), rim_get_msg_len (msg));
        if (res == RIM_OKAY)
        {
            // Create a message from reply, since the server packed key/value pairs and sent them back as a message
            rim_msg *rep = rim_new_msg (rim_cli_data(&req), req.data_len);
            char *k, *v;
            rim_num len;
            // Read the number of key/value pairs in the message, as it's the first piece of information we packed in srv.rim
            rim_read_msg (rep, &k, &v, &len);
            rim_num tmess = atol (v);
            free (k);
            int j;
            // read key/value pairs from the message sent back from the server
            for (j = 1; j <= tmess; j++)
            {
                rim_read_msg (rep, &k, &v, &len);
                printf("%s\n", v); // display value
                free (k);
            }
            free (rep);
        }
        // free up resources
        rim_cli_delete(&req);
        free (rim_get_msg(msg));
        free (msg);
    }
}
EOF

Compile C program:
gcc -o client client.c $(rim -i)

Run your C client
./client

The result is:
Reply is 1 (from message 1)
Reply is 1 (from message 1)
Reply is 2 (from message 2)
Reply is 1 (from message 1)
Reply is 2 (from message 2)
Reply is 3 (from message 3)
Reply is 1 (from message 1)
Reply is 2 (from message 2)
Reply is 3 (from message 3)
Reply is 4 (from message 4)
Reply is 1 (from message 1)
Reply is 2 (from message 2)
Reply is 3 (from message 3)
Reply is 4 (from message 4)
Reply is 5 (from message 5)
Reply is 1 (from message 1)
Reply is 2 (from message 2)
Reply is 3 (from message 3)
Reply is 4 (from message 4)
Reply is 5 (from message 5)
Reply is 6 (from message 6)
Reply is 1 (from message 1)
Reply is 2 (from message 2)
Reply is 3 (from message 3)
Reply is 4 (from message 4)
Reply is 5 (from message 5)
Reply is 6 (from message 6)
Reply is 7 (from message 7)
Reply is 1 (from message 1)
Reply is 2 (from message 2)
Reply is 3 (from message 3)
Reply is 4 (from message 4)
Reply is 5 (from message 5)
Reply is 6 (from message 6)
Reply is 7 (from message 7)
Reply is 8 (from message 8)
Reply is 1 (from message 1)
Reply is 2 (from message 2)
Reply is 3 (from message 3)
Reply is 4 (from message 4)
Reply is 5 (from message 5)
Reply is 6 (from message 6)
Reply is 7 (from message 7)
Reply is 8 (from message 8)
Reply is 9 (from message 9)



Copyright (c) 2019-2025 Gliim LLC. All contents on this web site is "AS IS" without warranties or guarantees of any kind.