客户端框架

更新时间:
2024-01-30
下载文档

客户端框架

本节介绍 VSOA 客户端框架的开发流、步骤和注意事项。

开发流程

创建客户端时,不同的开发语言在流程上略有区别,但总体都是按照如下步骤进行:

开发步骤

步骤 1:创建客户端

在使用 Java 、 JavaScript 和 Golang 的开发语言方式中,需要在创建客户端时指定其通信密码,而使用 C 的开发语言方式中是在连接服务端时指定通信密码。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef SYLIXOS
#include <sys/vproc.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include "vsoa_client.h"

static vsoa_client_t *client;

int main (int argc, char **argv)
{
#ifdef SYLIXOS
    vprocExitModeSet(getpid(), LW_VPROC_EXIT_FORCE);
#endif

    /*
    * Initilize client
    */
    client = vsoa_client_create(NULL, NULL);
    if (!client) {
        fprintf(stderr, "Can not create VSOA client!\n");
        return  (-1);
    }

    return  (0);
}
var vsoa = require('vsoa');

/* Client Option */
var option = { passwd: '123456' };

/* Client */
var client = new vsoa.Client(option);
import java.net.InetSocketAddress;

import com.acoinfo.vsoa.Client;
import com.acoinfo.vsoa.ClientOption;
import com.acoinfo.vsoa.Position;
import com.acoinfo.vsoa.Constant;
import com.acoinfo.vsoa.Error;
import com.acoinfo.vsoa.VsoaSocketAddress;

public class client_test {
    private  static String PASSWORD = "123456";

    public   static Client client;

    public static void main(String[] args) {

        /*
        * Initialize client
        */
        client = new Client(new ClientOption(PASSWORD, 6000, 4000, 3, false)) {

            @Override
            public void onError(Error error) {
                System.out.println("[CLIENT] Client error:" + error.message);
            }
        };
    }
}
package main

import (
    "gitee.com/sylixos/go-vsoa/client"
)

func ClientTest() {
    /*
    * Set client options' Password
    */
    clientOption := client.Option{
        Password: "123456",
    }

    /*
    * Create a new client instance
    */
    c := client.NewClient(clientOption)
}

func main() {
    ClientTest()
}

步骤 2:连接微服务

因为 VSOA 提供了 Position 位置服务功能,所以客户端可以使用微服务名称查询微服务的地址。

需要注意的是,需要指定 Position 位置服务的地址和端口,详情见 了解 VSOA 中的 "VSOA 位置服务配置方法",也可在代码中手动指定 Position 服务的位置。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef SYLIXOS
#include <sys/vproc.h>
#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include "vsoa_client.h"
#include "vsoa_position.h"

#define MY_SERVER_PASSWD "123456"

static vsoa_client_t *client;

int main (int argc, char **argv)
{
    char info[256];
    struct sockaddr_in addr;
    struct timespec timeout = { 1, 0 };
    socklen_t serv_len = sizeof(struct sockaddr_in);

#ifdef SYLIXOS
    vprocExitModeSet(getpid(), LW_VPROC_EXIT_FORCE);
#endif

    /*
    * Query VSOA server
    */
    if (!vsoa_position_lookup(AF_INET, "light_server",
                              (struct sockaddr *)&addr, &serv_len, NULL, &timeout)) {
        fprintf(stderr, "Can not found VSOA server!\n");
        return  (-1);
    }

    client = vsoa_client_create(NULL, NULL);
    if (!client) {
        fprintf(stderr, "Can not create VSOA client!\n");
        return  (-1);
    }

    /*
    * Connect to server with password
    */
    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);
    }

    return  (0);
}
/* Server name to connect */
var vsoa = require('vsoa');
var socket = require('socket');

/* Whether to manually query the Position server */
const POS_MANUALLY = false;

/* Server name to connect */
const SERVER_NAME = 'light_server';

/* Client Option */
var option = { passwd: '123456' };

/* Client */
var client = new vsoa.Client(option);

if (POS_MANUALLY) {
    /*
    * Set position server address
    */
    vsoa.Position.server({
        domain: socket.AF_INET, addr: '127.0.0.1', port: 3000
    });

    /*
    * Query VSOA server
    */
    vsoa.lookup(SERVER_NAME, function(error, saddr) {
        if (error) {
            console.error(`Could not find "${SERVER_NAME}" address!`);

        } else {
            console.log('Server address:', JSON.stringify(saddr));
            /*
            * Connect to server
            */
            client.connect(saddr);
        }
    });

} else {
    client.connect(`vsoa://${SERVER_NAME}`, error => {
        if (error) {
            console.warn('Connect error:', error.message);
        }
    });
}
import java.net.InetSocketAddress;

import com.acoinfo.vsoa.Client;
import com.acoinfo.vsoa.ClientOption;
import com.acoinfo.vsoa.Position;
import com.acoinfo.vsoa.Constant;
import com.acoinfo.vsoa.Error;
import com.acoinfo.vsoa.VsoaSocketAddress;

public class client_test {
    private  static boolean POS_MANUALLY  = false;
    private  static String  SERVER_NAME   = "light_server";
    private  static String  PASSWORD      = "123456";
    private  static String  POS_ADDRESS   = "127.0.0.1";
    private  static int     POS_PORT      = 3000;

    public   static Client client;

    public static void main(String[] args) {

        /*
        * Initialize client with password
        */
        client = new Client(new ClientOption(PASSWORD, 6000, 4000, 3, false)) {

            @Override
            public void onError(Error error) {
                System.out.println("Client error:" + error.message);
            }

            @Override
            public void onConnected(String info) {
                System.out.println("Connected with server:" + info);
            }
        };
 
        if (POS_MANUALLY) {
            VsoaSocketAddress address;
            try {
                
                /*
                * Query VSOA server
                */
                address = Position.lookup(new InetSocketAddress(POS_ADDRESS, POS_PORT), SERVER_NAME, 0);
                if (address == null) {
                    System.out.println("Could not find " + SERVER_NAME + " address!");
                    return;
                }
            } catch (Exception e) {
                System.out.println("Could not find " + SERVER_NAME + " address!");
                return;
            }

            System.out.println("Server address:" + address.toString());

            /*
            * Connect to server by address
            */
            if (!client.connect(address, null, Constant.VSOA_DEF_CONN_TIMEOUT)) {
                System.out.println("Connected with server failed" + address.toString());
                return;
            }
        } else {
            /*
            * Connect to server by URL
            */
            if (!client.connect("vsoa://" + SERVER_NAME, null, Constant.VSOA_DEF_CONN_TIMEOUT)) {
                System.out.println("Connected with server failed");
                return;
            }
        }
    }
}
package main

import (
    "fmt"

    "gitee.com/sylixos/go-vsoa/client"
)

var (
    positionAddr        = "localhost:3000"
    vsoaServerName = "vsoa://light_server"
)

func ClientTest() {
    /*
    * Set client options' Password
    */
    clientOption := client.Option{
        Password: "123456",
    }

    /*
    * Create a new client instance
    */
    c := client.NewClient(clientOption)

    /*
    * Set position server address
    */
    err := c.SetPosition(positionAddr)
    if err != nil {
        fmt.Println(err)
        return
    }

    /*
    * Query VSOA server & connect to server
    */
    _, err = c.Connect(client.Type_URL, vsoaServerName)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer c.Close()
}

func main() {
    ClientTest()
}

说明:
在 Node.js 的环境中,socket.AF_INET 应为 vsoa.AF_INET,详情可见 https://www.npmjs.com/package/vsoa 。

步骤 3:监听事件或循环

与 VSOA 微服务建立连接成功之后,它应当始终监听所有的 VSOA 输入事件。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef SYLIXOS
#include <sys/vproc.h>
#endif
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "vsoa_client.h"
#include "vsoa_position.h"

#define MY_SERVER_PASSWD "123456"

static vsoa_client_t *client;

int main (int argc, char **argv)
{
    int max_fd, cnt;
    fd_set fds;
    char info[256];
    socklen_t serv_len = sizeof(struct sockaddr_in);
    struct sockaddr_in addr;
    struct timespec timeout = { 1, 0 };

#ifdef SYLIXOS
    vprocExitModeSet(getpid(), LW_VPROC_EXIT_FORCE);
#endif

    if (!vsoa_position_lookup(AF_INET, "light_server",
                              (struct sockaddr *)&addr, &serv_len, NULL, &timeout)) {
        fprintf(stderr, "Can not found VSOA server!\n");
        return  (-1);
    }

    client = vsoa_client_create(NULL, NULL);
    if (!client) {
        fprintf(stderr, "Can not create VSOA client!\n");
        return  (-1);
    }

    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);
    }

    while (1) {
        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)) {
                vsoa_client_close(client);
                fprintf(stderr, "Connection lost!\n");
                return  (-1);
            }
        }
    }

    return  (0);
}
/* Server name to connect */
var vsoa = require('vsoa');
var socket = require('socket');

/* Whether to manually query the Position server */
const POS_MANUALLY = false;

/* Server name to connect */
const SERVER_NAME = 'light_server';

/* Client Option */
var option = { passwd: '123456' };

/* Client */
var client = new vsoa.Client(option);

if (POS_MANUALLY) {
    /*
    * Set position server address
    */
    vsoa.Position.server({
        domain: socket.AF_INET, addr: '127.0.0.1', port: 3000
    });

    /*
    * Query VSOA server
    */
    vsoa.lookup(SERVER_NAME, function(error, saddr) {
        if (error) {
            console.error(`Could not find "${SERVER_NAME}" address!`);

        } else {
            console.log('Server address:', JSON.stringify(saddr));
            /*
            * Connect to server
            */
            client.connect(saddr);
        }
    });

} else {
    client.connect(`vsoa://${SERVER_NAME}`, error => {
        if (error) {
            console.warn('Connect error:', error.message);
        }
    });
}

/*
 * Event loop
 */
require('iosched').forever();
import java.net.InetSocketAddress;

import com.acoinfo.vsoa.Client;
import com.acoinfo.vsoa.ClientOption;
import com.acoinfo.vsoa.Position;
import com.acoinfo.vsoa.Constant;
import com.acoinfo.vsoa.Error;
import com.acoinfo.vsoa.VsoaSocketAddress;

public class client_test {
    private  static boolean POS_MANUALLY  = true;
    private  static String  SERVER_NAME   = "light_server";
    private  static String  PASSWORD      = "123456";
    private  static String  POS_ADDRESS   = "127.0.0.1";
    private  static int     POS_PORT      = 3000;

    public   static Client client;

    public static void main(String[] args) {

        /*
        * Initialize client
        */
        client = new Client(new ClientOption(PASSWORD, 6000, 4000, 3, false)) {

            @Override
            public void onError(Error error) {
                System.out.println("Client error:" + error.message);
            }

            @Override
            public void onConnected(String info) {
                System.out.println("Connected with server:" + info);
            }
        };
 
        if (POS_MANUALLY) {
            VsoaSocketAddress address;
            try {
                address = Position.lookup(new InetSocketAddress(POS_ADDRESS, POS_PORT), SERVER_NAME, 0);
                if (address == null) {
                    System.out.println("Could not find " + SERVER_NAME + " address!");
                    return;
                }
            } catch (Exception e) {
                System.out.println("Could not find " + SERVER_NAME + " address!");
                return;
            }

            System.out.println("Server address:" + address.toString());

            if (!client.connect(address, null, Constant.VSOA_DEF_CONN_TIMEOUT)) {
                System.out.println("Connected with server failed" + address.toString());
                return;
            }
        } else {
            if (!client.connect("vsoa://" + SERVER_NAME, null, Constant.VSOA_DEF_CONN_TIMEOUT)) {
                System.out.println("Connected with server failed");
                return;
            }
        }

        while(true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}
package main

import (
    "fmt"
    "time"

    "gitee.com/sylixos/go-vsoa/client"
)

var (
    positionAddr        = "localhost:3000"
    vsoaServerName = "vsoa://light_server"
)

func ClientTest() {
    /*
    * Set client options' Password
    */
    clientOption := client.Option{
        Password: "123456",
    }

    /*
    * Create a new client instance
    */
    c := client.NewClient(clientOption)

    /*
    * Set position server address
    */
    err := c.SetPosition(positionAddr)
    if err != nil {
        fmt.Println(err)
        return
    }
    
    /*
    * Query VSOA server & connect to server
    */
    _, err = c.Connect(client.Type_URL, vsoaServerName)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer c.Close()
}

func main() {
    ClientTest()

    for {
        time.Sleep(1 * time.Second)
    }
}

说明:

在 Node.js 的环境中,不需要事件循环。

客户端机器人

由以上范例可见,使用 C 语言搭建 VSOA 客户端时步骤繁琐,且若服务端未启动时,客户端也将因连接服务端失败而不能正常运行。VSOA 提供了客户端机器人功能,客户端机器人可以自动连接指定的服务端并保持连接,使得开发者可以更加关注业务逻辑实现。

同样,在该范例中,因为独立的位置服务或 ECSM 的存在,不需要指定任何 IP 和端口信息。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef SYLIXOS
#include <sys/vproc.h>
#endif
#include "vsoa_cliauto.h"

/* My server password */
#define MY_SERVER_PASSWD "123456"

/* My client */
static vsoa_client_t *client;

/* My client auto */
static vsoa_client_auto_t *cliauto;

/*
 * main function
 */
int main (int argc, char **argv)
{
#ifdef SYLIXOS
    vprocExitModeSet(getpid(), LW_VPROC_EXIT_FORCE);
#endif

    /*
     * Create client auto robot
     */
    cliauto = vsoa_client_auto_create(NULL, NULL);
    client  = vsoa_client_auto_handle(cliauto);

    /*
     * Client auto robot start
     * The robot will automatically connect to the specified server and maintain the connection.
     * At this time, the developer only needs to focus on the business.
     */
    vsoa_client_auto_start(cliauto, "vsoa://light_server", MY_SERVER_PASSWD, 
                           NULL, 0, 1000, 1000, 1000);

    while (true) {
        sleep(1);
    }
}

说明:
VSOA 客户端机器人接口说明可参考 C 扩展编程手册

注意事项

C/C++ 客户端编译时需链接如下表所示的 VSOA 动态库,在 RealEvo-IDE 中配置时请参考 C/C++ 开发示例,Linux 下开发请参考 搭建 Linux 运行环境 提供的 C 语言范例进行配置。

库名称功能
libvsoa-json.so提供 JSON 功能
libvsoa-client.so提供客户端功能
libvsoa-parser.so提供参数解析功能
文档内容是否对您有所帮助?
有帮助
没帮助