VSOA 位置服务器提供了按服务名称查询 VSOA 服务器地址的功能,类似于 DNS 服务器,能有效简化客户端配置服务端地址的操作,并提高灵活性,为后面的故障自动迁移提供必要保证。位置模块 API 在 vsoa_position.h 和 libvsoa-position.so 中。
参考 hellovsoa 工程,创建 position 工程,工程源码修改如下:
#include #include #include #include #include #include "vsoa_position.h" #include "vsoa_platform.h" #define MY_SERVER_ADDR "127.0.0.1" #define MY_POSITION_SERVER_ADDR "127.0.0.1" #define MY_POSITION_SERVER_PORT (3000) static vsoa_position_server_t *pos_serv; static void query (void *arg, int domain, const char *query_name, vsoa_position_response_t *response) { struct sockaddr_in res; printf("query_name = %s\n", query_name); if (strcmp(query_name, "echo_server") == 0) { if (domain < 0 || domain == AF_INET) { bzero(&res, sizeof(struct sockaddr_in)); res.sin_family = AF_INET; res.sin_port = htons(4001); res.sin_addr.s_addr = inet_addr(MY_SERVER_ADDR); res.sin_len = sizeof(struct sockaddr_in); vsoa_position_server_response(pos_serv, response,(struct sockaddr *)&res,sizeof(res), false); } } } int main (int argc, char **argv) { int cnt, fd; fd_set fds; struct sockaddr_in pos_addr; /* * 创建位置服务对象 */ pos_serv = vsoa_position_server_create(query, NULL); /* * 启动位置服务对象 */ bzero(&pos_addr, sizeof(struct sockaddr_in)); pos_addr.sin_family = AF_INET; pos_addr.sin_port = htons(MY_POSITION_SERVER_PORT); pos_addr.sin_addr.s_addr = inet_addr(MY_POSITION_SERVER_ADDR); pos_addr.sin_len = sizeof(struct sockaddr_in); vsoa_position_server_start(pos_serv,(struct sockaddr *)&pos_addr,sizeof(struct sockaddr_in)); /* * 进入监听事件循环 */ while (1) { FD_ZERO(&fds); fd = vsoa_position_server_fd(pos_serv); if (fd < 0) { fprintf(stderr, "VSOA position server file error!\n"); return (-1); } FD_SET(fd, &fds); cnt = pselect(fd + 1, &fds, NULL, NULL, NULL, NULL); if (cnt > 0) { vsoa_position_server_input(pos_serv); } } return (0); } 源码分析:
服务端不使用位置服务,所以不需要修改源码。客户端可以直接配置服务端地址(如之前程序写的那样)也可以借助位置服务通过服务名称来自动获取服务端地址。
使用位置服务需要先配置位置服务地址,就是调用vsoa_position_server_start 函数时使用的地址,这样客户端才能先找到位置服务端,然后才能请求位置服务。配置位置服务地址有三种方式,且优先级地减,具体如下:
struct sockaddr_in。127.0.0.1:3000。 /etc/vsoa.pos 配置文件配置,可以配置多个位置服务地址,每行一个,形式如 127.0.0.1 3000。如果直接指定了位置服务器,则只查询指定的服务器,如果尚未指定位置服务器地址,则先自动使用环境变量 “VSOA_POS_SERVER” 进行查询,如果未找到,则将自动使用 “/etc/vsoa.pos” 中配置的服务器信息进行查询。
参考原 client 工程,创建新工程,工程源码修改如下,重点注意 49 到 55 行代码:
#include #include #include #include #include "vsoa_client.h" #include "vsoa_position.h" #define MY_SERVER_ADDR "127.0.0.1" #define MY_SERVER_PORT (4001) #define MY_SERVER_NAME "{\"name\":\"echo_server\"}" #define MY_SERVER_PASSWD "123456" #define MY_POSITION_SERVER_ADDR "127.0.0.1" #define MY_POSITION_SERVER_PORT (3000) static void on_command_echo (void *arg, struct vsoa_client *client, vsoa_header_t *vsoa_hdr, vsoa_payload_t *payload) { printf("echo message, param:%.*s, data:%.*s\n", (int)payload->param_len, payload->param, (int)payload->data_len, (char *)payload->data); } int main (int argc, char **argv) { bool ret; struct timespec timeout = {1, 0 }; vsoa_client_t *client; /* * 创建客户端 */ client = vsoa_client_create(NULL, NULL); if (!client) { fprintf(stderr, "Can not create VSOA client!\n"); return (-1); } /* * 连接服务端 */ struct sockaddr_in addr; socklen_t serv_len = sizeof(struct sockaddr_in); char info[256]; bzero(&addr, sizeof(struct sockaddr_in)); bzero(info, sizeof(info)); struct sockaddr_in pos_addr; pos_addr.sin_family = AF_INET; pos_addr.sin_port = htons(MY_POSITION_SERVER_PORT); pos_addr.sin_addr.s_addr = inet_addr(MY_POSITION_SERVER_ADDR); pos_addr.sin_len = sizeof(struct sockaddr_in); vsoa_position_lookup_server((struct sockaddr *)&pos_addr, serv_len); vsoa_position_lookup(AF_INET, "echo_server",(struct sockaddr *)&addr, &serv_len, NULL, &timeout); if (!vsoa_client_connect(client, (struct sockaddr *)&addr, sizeof(struct sockaddr_in), &timeout, MY_SERVER_PASSWD, info, sizeof(info))) { vsoa_client_close(client); fprintf(stderr, "Can not connect to VSOA server!\n"); return (-1); } printf("Server (%s) connected\n", info); /* * 注册异步RPC请求 */ vsoa_url_t url; vsoa_payload_t send; url.url = "/echo"; url.url_len = strlen(url.url); send.data = "1234567"; send.data_len = strlen(send.data); send.param = "abcdefg"; send.param_len = strlen(send.param); ret = vsoa_client_call(client, VSOA_CLIENT_RPC_METHOD_GET, &url, &send, on_command_echo, NULL, NULL); if (!ret) { fprintf(stderr, "Asynchronous RPC call error (not connected to server)!\n"); } /* * 进入监听事件循环 */ while (1) { int max_fd; int cnt; fd_set fds; FD_ZERO(&fds); max_fd = vsoa_client_fds(client, &fds); cnt = pselect(max_fd + 1, &fds, NULL, NULL, &timeout, NULL); if (cnt > 0) { if (!vsoa_client_input_fds(client, &fds)) { fprintf(stderr, "Connection lost!\n"); return (-1); } } } } 参考原 client_auto 工程,创建新工程,工程源码修改如下,重点注意 35 行代码 和之前的区别:
#include #include #include #include #include "vsoa_client.h" #include "vsoa_cliauto.h" #define MY_SERVER_PASSWD "123456" static void on_command_echo (void *arg, struct vsoa_client *client, vsoa_header_t *vsoa_hdr, vsoa_payload_t *payload) { printf("echo message, param:%.*s, data:%.*s\n", (int)payload->param_len, payload->param, (int)payload->data_len, (char *)payload->data); } int main (int argc, char **argv) { bool ret; vsoa_client_t *client; vsoa_client_auto_t *cliauto; /* * 创建客户端机器人 */ cliauto = vsoa_client_auto_create(NULL, NULL); /* * 由客户端机器人获取客户端对象 */ client = vsoa_client_auto_handle(cliauto); /* * 启动客户端机器人 */ vsoa_client_auto_start(cliauto, "vsoa://echo_server", MY_SERVER_PASSWD, NULL, 0, 1000, 1000, 1000); while (true) { /* * 检查客户端是否正常链接到服务端 */ if (vsoa_client_is_connect(client) == false) { continue; } /* * 注册异步RPC请求 */ vsoa_url_t url; vsoa_payload_t send; url.url = "/echo"; url.url_len = strlen(url.url); send.data = "1234567"; send.data_len = strlen(send.data); send.param = "abcdefg"; send.param_len = strlen(send.param); ret = vsoa_client_call(client, VSOA_CLIENT_RPC_METHOD_GET, &url, &send, on_command_echo, NULL, NULL); if (!ret) { fprintf(stderr, "Asynchronous RPC call error (not connected to server)!\n"); } sleep(1); } } 将上面的位置服务程序和两个客户端程序都编译部署,并运行,运行结果如下:
服务端运行情况:
位置服务端运行情况:
客户端 1 运行情况:
客户端 2 运行情况: