【VSOA】VSOA Server

VSOA Server

VSOA 服务器相关的所有 API 都包含在 vsoa_server.hlibvsoa-server.so 文件中。
libvsoa-hpserv.solibvsoa-server.so 是二进制兼容的,libvsoa-hpserv.so 提供了一个并行处理服务器,在多核处理器上可以更加高效地运行。建议使用符号链接来指定使用的库,以便应用程序不需要重新修改函数接口。

Notice

在 VSOA 服务器成功创建之后,下列函数为线程安全:

  • vsoa_server_count(),
  • vsoa_server_is_subscribed(),
  • vsoa_server_publish(),
  • vsoa_server_quick_publish(),
  • vsoa_server_cli_close(),
  • vsoa_server_cli_is_subscribed(),
  • vsoa_server_cli_address(),
  • vsoa_server_cli_reply(),
  • vsoa_server_cli_priority(),
  • vsoa_server_cli_keepalive(),
  • vsoa_server_cli_array(),
  • vsoa_server_cli_datagram(),
  • vsoa_server_cli_quick_datagram(),
  • vsoa_server_cli_send_timeout(),
  • vsoa_server_cli_set_authed(),
  • vsoa_server_cli_authed(),
  • vsoa_server_set_custom(),
  • vsoa_server_custom(),
  • vsoa_server_stream_create(),
  • vsoa_server_stream_accept(),
  • vsoa_server_stream_close().

所有回调函数都在 vsoa_server_input_fds() 中调用,因此需要注意多线程安全。

QoS 功能函数包括:

  • vsoa_server_cli_priority(),
  • vsoa_server_cli_send_timeout().

当与客户端的物理连接断开时,如果没有数据要发送,服务器无法知道客户端已断开连接,建议使用: vsoa_server_cli_keepalive() 进行客户端保活检测。

调用 vsoa_server_close() 后,服务器对象将不再可用,且只能在 vsoa_server_input_fds() 所在的事件循环中调用 vsoa_seerver_close(),而不能在其他回调中调用。

快速通道用于高频数据更新通道。
由于数据更新频率高,对通信可靠性的要求并不严格。

使用下列函数接口创建一个 VSOA 服务器:

vsoa_server_t *vsoa_server_create(const char *info_json);
  • 函数成功返回 server 句柄,失败返回 NULL
  • 参数 info_json: 服务器的信息,采用 json 格式。此 JSON 信息必须包含 name 字段;

使用示例

vsoa_server_t *s = vsoa_server_create("{\"name\":\"Test Server\"}");

使用下列函数接口关闭 VSOA 服务器:

void vsoa_server_close(vsoa_server_t *server);
  • 参数 server :VSOA 服务器对象句柄;

设置服务器连接密码:

bool vsoa_server_passwd(vsoa_server_t *server, const char *passwd);
  • 函数成功返回 true,失败返回 false
  • 参数server : VSOA 服务器句柄;
  • 参数 passwd : 配置的密码字符串;

服务器密码配置完成后,客户端必须提供正确的密码才能连接到此服务,否则,客户端连接请求将被服务器拒绝。
注意:密码是一个没有任何安全加密的字符串,在当前版本中只是一个相对简单的安全管理。

启动服务器:

bool vsoa_server_start(vsoa_server_t *server, const struct sockaddr *addr, socklen_t namelen);
  • 函数成功返回 true,失败返回 false
  • 参数 server :VSOA 服务器句柄;
  • 参数 addr :服务器地址,支持 AF_INET(结构体sockaddr_in)AF_INET6(结构体sockaddr_in6)
  • 参数 namelen :地址结构大小;

如果开始时绑定的端口为 0,系统将自动分配一个端口。此时,VSOA 服务器的 TCP和 UDP 端口是不同的,客户端需要使用版本 1.0.1 或更高版本来提供支持。

通过以下函数获取服务器地址:

bool vsoa_server_address(vsoa_server_t *server, struct sockaddr *addr, socklen_t *namelen);

同时还可以为服务器绑定网络接口,它可以在 vsoa_server_start 之前或 vsoa_server_start 之后调用:

bool vsoa_server_bind_if(vsoa_server_t *server, const char *ifname)

在服务器成功启动后,可以进入事件循环。

Server Event Loop

VSOA 服务器运行时,会始终使用以下两个 API 循环监视和处理所有输入事件:

int vsoa_server_fds(vsoa_server_t *server, fd_set *rfds);
void vsoa_server_input_fds(vsoa_server_t *server, const fd_set *rfds);
  • 参数 server:VSOA 服务器句柄;
  • 参数 rfds:需要监视的 VSOA 服务器中的所有事件;

使用示例

fd_set fds;
int custom_fd, max_fd, cnt;

while (1) {
    FD_ZERO(&fds);
    max_fd = vsoa_server_fds(my_server, &fds);

    /* add custom event */
    FD_SET(custom_fd, &fds);
    if (max_fd < custom_fd) {
        max_fd = custom_fd;
    }

    /* wait event */
    cnt = pselect(max_fd + 1, &fds, NULL, NULL, &timeout, NULL);
    if (cnt > 0) {
        vsoa_server_input_fds(my_server, &fds);
    }

    /* do other things */
}

以上代码实现了一个标准的事件循环模板,可以将任何自定义事件添加到这个循环中,非常简单和方便!

Remote Client Management

在 VSOA 服务器端,每个连接的客户端都被分配一个唯一的客户端 id:
In VSOA server side, each connected client will be assigned a unique client id:

typedef uint32_t  vsoa_cli_id_t;

服务器使用此 API 来监视客户端的连接状态:

void vsoa_server_on_cli(vsoa_server_t *server, vsoa_server_cli_func_t oncli, void *arg);
  • 参数 server:VSOA 服务器句柄;
  • 参数 oncli:当客户端同服务器连接或断开时,将调用该回调函数;
  • 参数 arg:可以使用这个回调参数来传递任何自定义信息;

回调函数原型 :

typedef void (*vsoa_server_cli_func_t)(void *arg, vsoa_server_t *server, vsoa_cli_id_t id, bool connect);
  • 参数 arg:回调参数来传递任何自定义信息;
  • 参数 server:VSOA 服务器句柄;
  • 参数 id:客户端 id;
  • 参数 connect:客户端连接状态;

可以获得连接到当前服务器的客户端总数:

int vsoa_server_count(vsoa_server_t *server);

还有一种方法可以获得所有客户端的 id:

int vsoa_server_cli_array(vsoa_server_t *server, vsoa_cli_id_t ids[], int max_cnt);
  • 函数成功返回实际的客户端数量,失败返回 -1;
  • 参数 server:VSOA 服务器句柄;
  • 参数 ids:存储客户端 id 的数组;
  • 参数 max_cnt:ids[] 数组大小;

可使用以下 API 获取客户端的地址:

bool vsoa_server_cli_address(vsoa_server_t *server, vsoa_cli_id_t id, struct sockaddr *addr, socklen_t *namelen);

为远程客户端设置一个连接存活检测计时器:

bool vsoa_server_cli_keepalive(vsoa_server_t *server, vsoa_cli_id_t id, int keepalive);
  • 函数成功返回 true,失败返回 false
  • 参数 server:VSOA 服务器句柄;
  • 参数 keepalive:将被用于 TCP_KEEPIDLETCP_KEEPINTVL

服务器可以主动关闭客户端:

bool vsoa_server_cli_close(vsoa_server_t *server, vsoa_cli_id_t id);
  • 函数成功返回 true,失败返回 false
  • 参数 server:VSOA 服务器句柄;
  • 参数 id:客户端id;

服务器可以获取指定的客户端是否订阅了指定的主题:

bool vsoa_server_cli_is_subscribed(vsoa_server_t *server, vsoa_cli_id_t id, const vsoa_url_t *url);
  • 客户端订阅时返回 true,未订阅时返回 false
  • 参数 server:VSOA 服务器句柄;
  • 参数 id:客户端 id;
  • 参数 url:指定的主题 url;

QoS

在VSOA中,有一个针对客户端的 QoS 机制:

bool vsoa_server_cli_priority(vsoa_server_t *server, vsoa_cli_id_t id, int new_prio);
  • 函数成功返回 true,失败返回 false
  • 参数 server:VSOA 服务器句柄;
  • 参数 id:客户端 id;
  • 参数 new_prio:新的优先级值,范围为 0(低)~5(高),默认值为 0

注意:客户端的优先级可以动态更新。

设置客户端数据包发送超时时间(默认在网络被阻塞时等待发送):

bool vsoa_server_cli_send_timeout(vsoa_server_t *server, vsoa_cli_id_t id, const struct timespec *timeout);
  • 函数成功返回 true,失败返回 false
  • 参数 server:VSOA 服务器句柄;
  • 参数 id:客户端id。;
  • 参数 timeout:设置的超时时间值;
    如果 timeout 值为 NULL,则表示使用默认的发送超时(100 ms)。如果连续三次发送超时,则连接将被断开。

配置或者获取客户端的授权状态:

bool vsoa_server_cli_set_authed(vsoa_server_t *server, vsoa_cli_id_t id, bool authed);
bool vsoa_server_cli_authed(vsoa_server_t *server, vsoa_cli_id_t id);

服务器可以设置并获取客户端的授权状态。当客户端连接到服务器并通过了密码检查时,客户端的身份验证状态为 true,此时可以同时接收服务器的发布信息。当服务器仍然需要执行其他独立授权检查时,当客户端刚刚连接时,此状态可以设置为 false,此时客户端将无法获取发布消息,直到客户端通过服务器的独立授权检查。

使用示例

vsoa_server_t *server;

...

void onclient(void *arg, vsoa_server_t *server, vsoa_cli_id_t id, bool connect)
{
    if (connect) {
        // We need independent authorization.
        vsoa_server_cli_set_authed(server, id, false);
    }
}

vsoa_server_on_cli(server, onclient, NULL);

/* Independent Authorization */
void onauth(void *arg, vsoa_server_t *server, vsoa_cli_id_t id, vsoa_header_t *vsoa_hdr, vsoa_url_t *url, vsoa_payload_t *payload)
{
    if (/* Independent Authorization Verify */) {
        vsoa_server_cli_set_authed(server, id, true);
        /* The authorization verification is successful, 
   * and the server's publish information can be received */
        vsoa_server_cli_reply(server, id, 0, vsoa_parser_get_seqno(vsoa_hdr), 0, NULL);

    } else {
        vsoa_server_cli_reply(server, id, AUTH ERROR CODE, vsoa_parser_get_seqno(vsoa_hdr), 0, NULL);
    }
}

vsoa_url_t url = { .url: "/auth", .url_len: 5 };

vsoa_server_add_listener(server, &url, onauth, NULL);

此功能在 VSOA 1.0.7 及更高版本中可用。


Base Data Struct

基本数据结构的定义在 vsoa_parser.h
服务器和客户端之间的所有数据交换都需要唯一的标识: URL

URL

typedef struct {
    char *url;
    size_t url_len;
} vsoa_url_t;
  • 参数 url:url字符串,必须从'/'开头,例如 "/res/a/b"
  • 参数 url_len:url的字符串长度;

使用示例

vsoa_url_t url;
...
url.url = "/res/a/b"
url.url_len = strlen(url.url);

Payload

Payload 结构用于 VSOA 中除流外的所有数据传输。

typedef struct {
    char *param;
    size_t param_len;
    void *data;
    size_t data_len;
} vsoa_payload_t;
  • 参数 param:字符串类型,可选项;
  • 参数 param_len:字符串长度,如果参数不存在需将其设置为 0
  • 参数 data:原始数据类型,可选项;
  • 参数 data_len:数据的长度,如果参数不存在需将其设置为 0

注意:我们强烈建议使用 JSON 格式作为 param 参数,并且可以轻松地使用 jstruct工具来解析/组合参数 param。对于这些数据,你可以使用 binary 格式(应考虑端序)或 base64 格式。

VSOA Packet Header

typedef struct {...} vsoa_header_t;

该结构体的成员一般不要直接访问,可以借助一些辅助程序宏:

#define vsoa_parser_get_seqno(vsoa_hdr)         ...
#define vsoa_parser_get_type(vsoa_hdr)          ...
#define vsoa_parser_get_flags(vsoa_hdr)         ...
#define vsoa_parser_get_status(vsoa_hdr)        ...
#define vsoa_parser_get_tunid(vsoa_hdr)         ...
#define vsoa_parser_get_url_len(vsoa_hdr)       ...
#define vsoa_parser_get_param_len(vsoa_hdr)     ...
#define vsoa_parser_get_data_len(vsoa_hdr)      ...
  • seqno: 对于 RPC 来说是确保 RPC 相关业务完整性的一个非常重要的信息,因为 RPC 可以异步并行调用。
  • type: 由VSOA核心使用,用户不必关心;
  • flags: 可以从flags中获得的RPC方法:VSOA_FLAG_SET
  • status: RPC从服务器返回的代码,下表中数值为当前默认定义:
状态码描述
vsoa.code.SUCCESS0调用成功
vsoa.code.PASSWORD1密码错误
vsoa.code.ARGUMENTS2参数错误
vsoa.code.INVALID_URL3无效的URL
vsoa.code.NO_RESPONDING4服务器未响应
vsoa.code.NO_PERMISSIONS5没有权限
vsoa.code.NO_MEMORY6内存不足
vsoa.code.PROXY7代理错误 (payload.param.error 指示错误消息)

您还可以定义您自己的状态代码。用户定义的故障值建议为128 ~ 254

  • tunid: 隧道id,用于流传输,后面章节会有更多细节描述。
  • url_len: url的长度,由VSOA核心使用。
  • param_len: 参数的长度,由VSOA核心使用。
  • data_len: 数据的长度,由VSOA核心使用。

使用以下API打印标题信息:

void vsoa_parser_print_header(const vsoa_header_t *vsoa_hdr, bool data_detail);
  • 参数 vsoa_hdr:VSOA头指针;
  • 参数 data_detail:以十六进制格式打印数据;

Server Publish

bool vsoa_server_publish(vsoa_server_t *server, const vsoa_url_t *url, const vsoa_payload_t *payload);
  • 函数成功返回 true,失败返回 false
  • 参数 url:当前 payload 对应的 url;
  • 参数 payload:需要发布的 payload 数据;

如果需要大量且高频的数据发布,但对传输可靠性的要求并不严格,可以使用以下发布接口:

bool vsoa_server_quick_publish(vsoa_server_t *server, const vsoa_url_t *url, const vsoa_payload_t *payload);

在发布一个 url 之前,建议检查是否有客户端需要此 url 数据,如果没有,服务器则不需要进行发布:

bool vsoa_server_is_subscribed(vsoa_server_t *server, const vsoa_url_t *url);
  • 有客户端订阅时,函数返回 true,否则返回 false
  • 参数 server:VSOA 服务器句柄;
  • 参数 url:需要查询的 url;

使用示例

vsoa_server_t *server;
vsoa_url_t url;
vsoa_payload_t payload;

if (!vsoa_server_is_subscribed(server, &url)) {
    return;
}

vsoa_server_publish(server, &url, &payload);

注意:URL匹配:URL使用 '/'作为分隔符,例如:'/a/b/c'。如果客户端订阅'/a/',服务器发布'/a''/a/b''/a/b/c'消息,则客户端都将收到。

Server RPC

服务器应该首先为 RPC 的 URL 添加一个监听器:

bool vsoa_server_add_listener(vsoa_server_t *server, const vsoa_url_t *url, vsoa_server_cmd_func_t callback, void *arg);
  • 有客户端订阅时,函数返回 true,否则返回 false
  • 参数 server:VSOA 服务器句柄;
  • 参数 url:url 信息;
  • 参数 callback:当服务器监测到 RPC 从客户端到达时,此回调将被调用;
  • 参数 arg:回调函数的参数;

监听器回调原型:

typedef void (*vsoa_server_cmd_func_t)(void *arg, vsoa_server_t *server, vsoa_cli_id_t id, vsoa_header_t *vsoa_hdr, vsoa_url_t *url, vsoa_payload_t *payload);
  • 参数 arg:回调函数的参数;
  • 参数 server:VSOA 服务器句柄;
  • 参数 id:客户端id;
  • 参数 vsoa_hdr:VSOA 标准数据头;
  • 参数 url:请求的 url 信息;
  • 参数 payload:来自客户端的 payload 数据;

可以使用下列 API 动态删除 RPC 监听器:

void vsoa_server_remove_listener(vsoa_server_t *server, const vsoa_url_t *url);

当 RPC 数据到达时,服务器使用以下 API 来回复客户端:

bool vsoa_server_cli_reply(vsoa_server_t *server, vsoa_cli_id_t id, uint8_t status, uint32_t seqno, uint16_t tunid, const vsoa_payload_t *payload);
  • 函数成功返回 true,失败返回 false
  • 参数 server:VSOA 服务器句柄;
  • 参数 id:客户端 id;
  • 参数 status:VSOA 状态码;
  • 参数 seqno:与 RPC 请求相同;
  • 参数 tunid:用于流传输;
  • 参数 payload:对客户端的 payload,可以为 NULL

通常,服务器在RPC监听器回调函数中回复客户端。

使用示例

vsoa_server_t *server;
vsoa_url_t url;

url.url     = "/read";
url.url_len = strlen(url.url);
vsoa_server_add_listener(my_server.server, &url, command_read, NULL);

void command_read (void *arg, vsoa_server_t *server, vsoa_cli_id_t cid, vsoa_header_t *vsoa_hdr, vsoa_url_t *url, vsoa_payload_t *payload)
{
    /* note: get the seqno from header */
    uint32_t seqno = vsoa_parser_get_seqno(vsoa_hdr); 
    vsoa_payload_t payload_reply;

    /* do somthing */

    /* reply to client */
    vsoa_server_cli_reply(server, cid, 0, seqno, 0, &payload_reply);
}

RPC URL 匹配规则

PATHRPC URL 匹配规则
"/"默认URL监听器
"/a/b/c"仅处理 "/a/b/c" 路径的调用
"/a/b/c/"处理 "/a/b/c""/a/b/c/..." 所有路径调用

注意:如果 "/a/b/c""/a/b/c/" RPC处理程序同时存在,当客户端进行 "/a/b/c" RPC调用时,"/a/b/c" 处理程序会在 "/a/b/c/" 处理程序之前完成匹配并进行处理。

Server Stream

一个流实际上是一个新的 TCP 连接通道:

vsoa_server_stream_t *vsoa_server_stream_create(vsoa_server_t *server);
  • 函数成功返回流对象
  • 参数 server:VSOA 服务器句柄;

stream 结构体:

typedef struct vsoa_server_stream {
    bool valid;
    int listenfd;
    int clifd;
    uint16_t tunid;
    void *custom;
} vsoa_server_stream_t;
  • 参数 valid:识别该流对象是否有效,由VSOA核心使用;
  • 参数 listenfd:服务器使用此句柄来监听及接受客户端的连接;
  • 参数 clifd:连接后的客户端句柄;
  • 参数 tunid:新的TCP通道,服务器使用该通道回复客户端,客户端使用该通道连接到服务器;
  • 参数 custom:自定义参数;

服务器使用以下API来接受客户端连接:

int vsoa_server_stream_accept(vsoa_server_stream_t *stream, struct sockaddr *addr, socklen_t *namelen, int keepalive);
  • 函数成功返回 客户端句柄(服务器使用此句柄进行后续流传输),失败返回负数;
  • 参数 stream:流对象;
  • 参数 addr:存储一个新的客户端连接地址,可以为NULL
  • 参数 namelen:存储 addr 的长度,可以为NULL
  • 参数 keepalive:将被用于TCP_KEEPIDLETCP_KEEPINTVL(参考函数vsoa_server_cli_keepalive);

完成流传输后,服务器应关闭该流:

void vsoa_server_stream_close(vsoa_server_stream_t *stream);

当流对象被关闭后,不允许再次被使用。

注意:我们强烈建议您为一个流分配一个独立的线程,以避免阻止正常的RPC请求。
更多细节,请参考 example/c/stream.c

Server Datagram

DATAGRAM(数据报)是另一种传输类型,通常这种类型的数据用于传输一些不需要确认的数据,例如,VSOA的数据报数据包可以用于构建VPN网络。
服务器向客户端发送数据报,这个API与vsoa_server_cli_reply()非常相似,但是没有statusseqnotunid参数。

bool vsoa_server_cli_datagram(vsoa_server_t *server, vsoa_cli_id_t id, const vsoa_url_t *url, const vsoa_payload_t *payload);
  • 函数成功返回 true,失败返回 false
  • 参数 server:VSOA 服务器句柄;
  • 参数 id:客户端 id;
  • 参数 url :url 信息;
  • 参数 payload:对客户端的 payload,可以为 NULL

使用以下 API 可以通过快速通道向客户端发送数据报:

bool vsoa_server_cli_quick_datagram(vsoa_server_t *server, vsoa_cli_id_t id, const vsoa_url_t *url, const vsoa_payload_t *payload);

服务器接收来自客户端的数据报:

void vsoa_server_on_datagram(vsoa_server_t *server, vsoa_server_dat_func_t callback, void *arg);
  • 参数 server:VSOA 服务器句柄;
  • 参数 callback :回调函数,当数据报到达服务器端该回调函数会被调用;
  • 参数 arg :回调函数参数;

回调函数原型:

typedef void (*vsoa_server_dat_func_t)(void *arg, vsoa_server_t *server, vsoa_cli_id_t id, vsoa_url_t *url, vsoa_payload_t *payload, bool quick);

Custom Data Bind

使用下列两个函数可以绑定和扩展服务框架。

bool vsoa_server_cli_set_custom(vsoa_server_t *server, vsoa_cli_id_t id, void *custom);
void *vsoa_server_cli_custom(vsoa_server_t *server, vsoa_cli_id_t id);

VSOA Server Parameter Synchronizer

此功能可协助VSOA服务器同步数据并减少数据同步代码。在C版本中,它们被设计成宏,以便于适应不同的数据类型。它们在文件: libvsoa/vsoa_syncer.h

同步器返回值:

宏定义
VSOA_SYNCER_PUB_OK0
VSOA_SYNCER_SET_OK1
VSOA_SYNCER_GET_OK2
VSOA_SYNCER_ERROR-1

Publish Syncer

当有任何客户端订阅时,它将作为标准方式自动发布URL的数据。

vsoa_syncer_ret VSOA_PARAM_SYNCER_PUBLISH(server, url, module, struc, bin, bin_len);
  • 函数返回状态代码,成功回复 VSOA_SYNCER_PUB_OK,失败回复 “VSOA_SYNCER_ERROR”;+ 参数 server:VSOA 服务器句柄;
  • 参数 url:URL 信息;
  • 参数 module:数据类型模块前缀(由jstruct自动生成);
  • 参数 struc:数据类型的对象;
  • 参数 bin:payload 数据;
  • 参数 bin_len:payload 数据的长度;

RPC Syncer

vsoa_syncer_ret VSOA_PARAM_SYNCER_RPC(server, cli_id, module, struc, vsoa_header, payload, checker, arg);

如果获取请求方法,此函数将自动回复RPC请求。如果设置了该方法,此函数将自动解析和同步数据,并将最新的数据发布到所有其他客户端。

  • 函数返回值可能是 VSOA_SYNCER_SET_OKVSOA_SYNCER_GET_OKVSOA SYNCER ERROR
  • 参数 server:VSOA 服务器句柄;
  • 参数 cli_id:客户端 id;
  • 参数 module:数据类型模块前缀(由 jstruct 自动生成);
  • 参数 struc:数据类型的对象;
  • 参数 vsoa_header :RPC 数据头;
  • 参数 payload:payload 数据;
  • 参数 checker:这是一个针对自定义有效检查的回调函数;
  • 参数 arg:checker 的参数;
  • 该函数可通过 RPC(vsoa_server_cli_reply()函数) 回复客户端状态代码,成功回复 VSOA_STATUS_SUCCESS,否则回复其他相应状态;

注意: checker 的函数原型是:

uint8_t (*checker) (void *arg, void *struc, vsoa_payload_t *payload);
  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
这段代码使用了C语言来进行网络编程。以下是对代码中各行的解释: 1. `char info[256];`:声明了一个名为`info`的字符数组,长度为256,用于存储信息。 2. `socklen_t serv_len;`:声明了一个类型为`socklen_t`的变量`serv_len`,用于存储服务器地址的长度。 3. `vsoa_client_t *client;`:声明了一个指向`vsoa_client_t`类型的指针变量`client`,用于存储客户端的信息。 4. `struct sockaddr_in pos_addr, serv_addr;`:声明了两个类型为`struct sockaddr_in`的变量`pos_addr`和`serv_addr`,用于存储服务器和本地地址信息。 5. `struct timespec timeout = { 1, 0 };`:声明了一个类型为`struct timespec`的变量`timeout`,用于设置超时时间。 6. `bzero(&pos_addr, sizeof(struct sockaddr_in));`:将`pos_addr`变量所占内存空间清零。 7. `pos_addr.sin_family = AF_INET;`:设置`pos_addr`中的地址族为IPv4。 8. `pos_addr.sin_port = htons(5000);`:设置`pos_addr`中的端口号为5000,并通过函数`htons()`将端口号转换为网络字节序。 9. `pos_addr.sin_addr.s_addr = inet_addr("127.0.0.1");`:设置`pos_addr`中的IP地址为本地回环地址"127.0.0.1"。 10. `pos_addr.sin_len = sizeof(struct sockaddr_in);`:设置`pos_addr`的长度为`struct sockaddr_in`的长度。 11. `vsoa_position_lookup_server((struct sockaddr *)&pos_addr, sizeof(struct sockaddr_in));`:调用函数`vsoa_position_lookup_server()`,向服务器查询位置信息。将`pos_addr`的地址转换为`struct sockaddr`类型的指针,并传递给函数。 12. `vsoa_position_lookup(AF_INET, "vsoa.myserver.com", (struct sockaddr *)&serv_addr, &serv_len, NULL, &timeout);`:调用函数`vsoa_position_lookup()`,向名为"vsoa.myserver.com"的服务器查询位置信息。将服务器地址存储到`serv_addr`中,同时获取服务器地址的长度存储到`serv_len`中,并设置超时时间为1秒。 总之,这段代码使用了网络编程相关的函数和结构体来实现与服务器通信并查询位置信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ScilogyHunter

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值