2013/01/30

[工作點滴] protocal buffer examples

There is protobuf and protobuf-c web site.

Now we are implementing this way that can be remote control from back-end applications.
The protobuf-c has some extension from google's protobuf and we can add the RPC funtion for further.

The first experiment is using the message directly. We pack the message into a share memory between the server and the client. Both side can get the message no problem.

But our target is to use the RPC way that protobuf-c provided. If we want to use the protobuf-c, we have to create the .proto file first. Here is an example. We create a 'statusapi.proto'.

package statusapi;
message StatusRequestType {}
message StatusResponseType {}
message StatusParams {
    optional int32 zoom_status = 1 [default = 0];
    optional int32 focus_status = 2 [default = 0];
}
service Status {
    rpc set_status (StatusParams) returns (StatusResponseType);
    rpc get_status (StatusRequestType) returns (StatusParams);
}


By using the protobuf-c tool withe following command to generate the source code.
# ./protobuf-c --c_out=. statusapi.proto

The statusapi.pb-c.c and statusapi.pb-c.h are created in the folder. This is the basic functions we have.
Now lets doing the RPC server and client for further test.

status_server.c
#include <stdio.h>
#include <string.h>
#include <statusapi.pb-c.h>

PROTOBUF_C_BEGIN_DECLS
#include <google/protobuf-c/protobuf-c-rpc.h>
PROTOBUF_C_END_DECLS

static ProtobufC_RPC_Server *server;
static Statusapi__StatusParams status_params = STATUSAPI__STATUS_PARAMS__INIT;

void statusapi__set_status(Statusapi__Status_Service *service,
                                         const Statusapi__StatusParams *input,
                                         Statusapi__StatusResponseType_Closure closure,
                                         void *closure_data)
{
    fprintf(stderr,"set status.\n");
    if (input->has_zoom_status) {
        fprintf(stderr,"zstatus=%d.\n", input->zoom_status);
        status_params.has_zoom_status=input->has_zoom_status;
        status_params.zoom_status=input->zoom_status;
    }

    if (input->has_focus_status) {
        fprintf(stderr,"fstatus=%d.\n", input->focus_status);
        status_params.has_focus_status=input->has_focus_status;
        status_params.focus_status=input->focus_status;
    }
    closure (NULL, closure_data);
}

void statusapi__get_status(Statusapi__Status_Service *service,
                                         const Statusapi__StatusRequestType *input,
                                         Statusapi__StatusParams_Closure closure,
                                         void *closure_data)
{
    fprintf(stderr,"get status!!\n");
    closure (&status_params, closure_data);
}

Statusapi__Status_Service statusapi_service = STATUSAPI__STATUS__INIT(statusapi__);

int main(int argc, char *argv[])
{
    /* Create a server and wait for the client to connect. */
    server = protobuf_c_rpc_server_new (PROTOBUF_C_RPC_ADDRESS_LOCAL,
                                                                "status_rpc.socket",
                                                                (ProtobufCService *)&statusapi_service,
                                                                NULL);
    while(1) {
        protobuf_c_dispatch_run(protobuf_c_dispatch_default());
    }
    return 0;
}


status_client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <statusapi.pb-c.h>

PROTOBUF_C_BEGIN_DECLS
#include <google/protobuf-c/protobuf-c-rpc.h>
PROTOBUF_C_END_DECLS

static void status_set_response (const Statusapi__StatusResponseType *response,
                                                 void *closure_data)
{
    if (response == NULL) {
        fprintf(stderr, "Error processing request.\n");
    } else {
        fprintf(stderr, "server set status params response.\n");
    }
    *(protobuf_c_boolean *)closure_data = 1;
}

static void status_get_response (const Statusapi__StatusParams *response,
                                                 void *closure_data)
{
    if (response == NULL) {
        fprintf(stderr, "Error processing request.\n");
    } else {
        fprintf(stderr, "server get status params response.\n");
    }
    fprintf(stderr,"get status.\n");
    if (response->has_zoom_status) {
        fprintf(stderr,"zstatus=%d.\n", response->zoom_status);
    }
    if (response->has_focus_status) {
        fprintf(stderr,"fstatus=%d.\n", response->focus_status);
    }
    *(protobuf_c_boolean *)closure_data = 1;
}

int main (int argc, const char * argv[])
{
    ProtobufCService *service;
    ProtobufC_RPC_Client *client;
    protobuf_c_boolean is_done;
    Statusapi__StatusRequestType request = STATUSAPI__STATUS_REQUEST_TYPE__INIT;
    Statusapi__StatusParams status_params_request = STATUSAPI__STATUS_PARAMS__INIT;
    int test_count;

    // create a client service to stop the extapi thread.
    service = protobuf_c_rpc_client_new (PROTOBUF_C_RPC_ADDRESS_LOCAL,
                                                               "status_rpc.socket",
                                                               &statusapi__status__descriptor,
                                                               NULL);
    if (service == NULL) {
        // check later if this situation happen, what will going on??
        fprintf(stderr,"error creating client\n");
    }

    client = (ProtobufC_RPC_Client *)service;
    while (!protobuf_c_rpc_client_is_connected (client)) {
        protobuf_c_dispatch_run(protobuf_c_dispatch_default());
    }

    test_count = 256;
    while(test_count--) {
        statusapi__status_params__init(&status_params_request);
        status_params_request.has_zoom_status = 1;
        status_params_request.zoom_status = test_count;
        status_params_request.has_focus_status = 1;
        status_params_request.focus_status = test_count;
        // set status params to server.
        is_done = 0;
        statusapi__status__set_status(service, &status_params_request, status_set_response, &is_done);
        while (!is_done) {
            protobuf_c_dispatch_run (protobuf_c_dispatch_default());
        }
        // get staus params from server.
        is_done = 0;
        statusapi__status__get_status(service, &request, status_get_response, &is_done);
        while (!is_done) {
            protobuf_c_dispatch_run (protobuf_c_dispatch_default());
        }
    }
    // destroy the service.
    protobuf_c_service_destroy(service);
    return 0;
}

Prepare two terminal windows. One execute the status_server and another one execute the status_client. The client send the parameters set message to server and the server save the contents in local variables. Then the client send the parameters get message to server and the server return the contents to the clients.

Later, let's talk more detailed about the functions that protobuf-c provided.



沒有留言: