Bean(WebSocket)通讯
# FastWeb Bean(WebSocket)通讯
Bean之间的通讯依赖于WebSocket通信,当Bean启动并运行时,会向FastWeb服务器发起WebSocket连接,直至页面被关闭前,均会保持连接的状态。
接下来将介绍FastWeb中的WebSocket通讯方式,以及如何在Bean,Smart、PinToo,第三方客户端中实现WebSocket通讯。
# 1. WebSocket概述
在说明Bean的通讯方式前,我们要了解WebSocket是什么,为什么使用WebSocket,以及WebSocket的连接特性。
# 1.1. 什么是WebSocket?
在介绍WebSocket之前,我们要先了解一下HTTP。
HTTP连接是由客户端发起,服务器在接收到客户端的请求后向客户端发送响应信息。HTTP的协议存在一个缺陷,就是通信只能由客户端发起,服务器不能主动向客户端推送信息。如果服务器有连续状态变化时,客户端想要获知会变得很麻烦,只能使用轮询等查询方式向服务端发送请求来获取信息,这种方式不仅不能及时获知服务器状态,还严重影响服务器的运行效率。
WebSocket 协议在2008年诞生,2011年成为国际标准。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话。
# 1.2. FastWeb 上的WebSocket通信
FastWeb内置了WebSocket服务器,用户使用浏览器打开FastWeb时,FastWeb浏览器的客户端会与服务端发起WebSocket连接,连接会一直保持直至用户关闭浏览器。
# 2. 配置WebSocket服务器
WebSocket服务器的配置位于 配置中心 。在配置中心界面,点击 WebSocket
选项卡,设置WebSocket服务器的信息。 请注意,FastWeb默认未开启,请在 FastWebClient WebSocket 中勾选 开启
选项。
设置完成后,点击 [保存]
按钮,切换至 普通服务器
选项卡,点击下方 [重启]
按钮重新启动FastWeb。
在上述示例中生成的WebSocket地址为 ws://127.0.0.1:8805/message
,SSL WebSocket地址为 wss://127.0.0.1:8806/message
。接下来测试连接的连通性。使用 WebSocket在线测试工具 (opens new window) 进行测试,输入地址后,点击 [连接]
按钮,如出现连接成功的字样,表示连接成功。
如使用了身份验证,则应使用以下地址进行身份认证连接。其中的 {USERNAME}
与 {PASSWORD}
处请修改为配置中心中定义的用户名与密码。
ws://localhost:8805/sgc/auth/url/{USERNAME}/{PASSWORD}
wss://localhost:8806/sgc/auth/url/{USERNAME}/{PASSWORD}
# 3. Bean通信方式
在FastWeb中,WebSocket是Bean的重要通讯工具,Bean模块之间的通讯交互以WebSocket为基础。爱招飞的开发平台 Smart 与 PinToo、开发板(Arduino、ESP8266、ESP32等)、FastWeb平台均支持WebSocket通信,通过WebSocket连接可实现Bean的互联互通。接下来将介绍在不同协议与FastWeb的WebSocket通信的方法。
# 3.1. Bean
以下内容对包含浏览器功能的 Smart 与 PinToo 同样适用。
FastWeb平台内置两个自定函数 SendWsMsgBySId 、SendWsMsg 用于Bean模块之间的消息传送。下面将以 Bean-demo1
、Bean-demo2
两个带有图形的模块为例进行说明。
Bean之间消息传输流程如下。
- 发送信息
Bean-demo1
模块通过调用 SendWsMsgBySId 或 SendWsMsg ,向服务器发送WebSocket信息。
- 解析并传送消息
FastWeb的WebSocket服务器接收到来自 Bean-demo1
模块发送的WebSocket信息,解析后读取json信息,根据传送的目标用户或者目标会话的信息,从已连接的Bean列表中查找匹配的用户或者会话。如果找到匹配的用户会话,就会向目标用户会话 (如 Bean-demo2
) 发送WebSocket 信息。
- 接收并解析,触发动作
Bean-demo2
接收到来自FastWeb的消息后,解析并触发模块窗体的 OnAjaxEvent
事件,事件的名称 eventname
以及 数据 data
均由json定义。在 OnAjaxEvent
事件中可使用 params.Values["paramname"]
来读取键值对的数据信息。示例代码如下。
//JScript
function UgWebRunFrameOnAjaxEvent(sender,eventname,params)
{
if (SameText(eventname,"update")) //解读接收到的eventname ,此处的eventname要与发送端的callbackeventname 或者
{
var user = params.Values["user"];
var msg = params.Values["message"];
ugmemo01.Lines.Add(user+" "+ formatdatetime("c",now()) + ":");
ugmemo01.Lines.Add(msg);
ugmemo01.Lines.Add("");
}
}
2
3
4
5
6
7
8
9
10
11
12
//PasScript
procedure UgWebRunFrameOnAjaxEvent(sender:tobject;eventname,params:string);
var
user,msg: string;
begin
if (SameText(eventname,'update')) then
begin
user := params.Values['user'];
msg := params.Values['message'];
ugmemo01.Lines.Add(user+' '+ formatdatetime('c',now()) + ':');
ugmemo01.Lines.Add(msg);
ugmemo01.Lines.Add('');
end;
end;
2
3
4
5
6
7
8
9
10
11
12
13
14
// Make sure to add code blocks to your code group
# 3.2. WebSocket
Bean通信可使用传统的WebSocket协议来进行。支持WebSocket客户端通讯的有 Smart 与 PinToo、开发板(Arduino、ESP8266、ESP32等)。
通信的流程如下。
- 登录并注册会话
WebSocket客户端在连接至FastWeb的WebSocket服务器后,需注册会话才可进行后续的信息传输。注册会话json格式如下。
{"action":"login","sid":"wstest"}
通过以上注册,WebSocket获得了一个名为 wstest
的会话ID,可进行数据交互的传输。
- 发送WebSocket消息
WebSocket传输的是一串格式化的json字符串,示例如下。
{
"username": "demo", //WebSocket消息发送的目标用户
"action": "callback", //WebSocket消息告知Bean执行的动作
"tag": "0", //URL参数定义的标识组,可用于区分同一个IsoBean的不同场景的实例
"data": {
"callbackcomponent": "wb-vis-0008_chatroom", //执行动作的目标Bean模块的名称
"callbackeventname": "update", //执行触发OnAjaxEvent事件的 eventname(事件名称)
"callbackparams": [ //传输的键值,可以有一对或者多对
{
"paramname": "user", //WS参数1名称
"paramvalue": "demo" //WS参数1取值
},
{
"paramname": "message", //WS参数2名称
"paramvalue": "212" //WS参数2取值
}
]
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- 解析并传送消息
FastWeb的WebSocket服务器接收到WebSocket信息,解析后读取json信息,根据传送的目标用户信息,从已连接的Bean列表中查找匹配的用户。如果找到匹配的用户,就会向目标用户发送WebSocket 信息。
- 接收并解析,触发动作
Bean模块接收到来自FastWeb的消息后,解析并触发模块窗体的 OnAjaxEvent
事件,事件的名称 eventname
以及 数据键值对 paramname=paramvalue
均由json定义。在 OnAjaxEvent
事件中可使用 params.Values["paramname"]
来读取键值对的数据信息。示例代码请参考 FastWeb 部分 接收并解析,触发动作
的代码。
- 向WebSocket客户端发送信息
Bean可使用 SendWsMsgBySId 来向WebSocket客户端发送信息。向WebSocket客户端发送信息只需要指定 sid
,参数 msg
可任意填写。调用此函数发送时,Bean 向FastWeb 的 WebSocket 服务器发送信息。
- 解析并传送消息
FastWeb的WebSocket服务器接收到WebSocket信息,根据传送的目标会话ID,从已连接列表中查找匹配的会话ID。如果找到匹配的会话ID,就会向目标会话ID发送WebSocket 信息。
- WebSocket客户端接收处理信息
WebSocket客户端从服务端接收到 msg
消息,可自行设计相关的事件来处理接收的消息,实现Bean远程控制的目的。
如果是非FastWeb的WebSocket客户端需要通过WebSocket服务器向其他非FastWeb客户端发送消息的,可在经过步骤1注册会话的动作后,通过WebSocket发送以下内容格式的json来实现。
{
"action":"msg", //动作类型
"sid":"smart", //发送的目标会话ID
"text":"Hello Smart Client" //发送的信息
}
2
3
4
5
上述消息发送后,在目标的WebSocket客户端(Smart、PinToo、FastERP或者ESP32开发板等)可接收到 Hello Smart Client
的消息。
# 3.3. RestAPI
Bean支持通过RestAPI来接收信息,并将其转换为 WebSocket 消息发送给目标用户的Bean模块。
- 发送信息
RestAPI的请求Url示例如下。
POST
http://localhost:8888/?restapi=sendwsmsg
2
POST的请求体中包含以下内容。
{
"username": "demo", //WebSocket消息发送的目标用户
"action": "callback", //WebSocket消息告知Bean执行的动作
"tag": "0", //URL参数定义的标识组,可用于区分同一个IsoBean的不同场景的实例
"data": {
"callbackcomponent": "wb-vis-0008_chatroom", //执行动作的目标Bean模块的名称
"callbackeventname": "update", //执行触发OnAjaxEvent事件的 eventname(事件名称)
"callbackparams": [ //传输的键值,可以有一对或者多对
{
"paramname": "user", //WS参数1名称
"paramvalue": "demo" //WS参数1取值
},
{
"paramname": "message", //WS参数2名称
"paramvalue": "212" //WS参数2取值
}
]
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
发送以上请求后,观察反馈的结果,如果结果为以下内容,则信息已成功提交。
{
"status": "ok",
"message": "successfully"
}
2
3
4
- 解析并传送消息
FastWeb的RestAPI接收到此信息后进行解析,根据传送的目标用户信息,从已连接的Bean列表中查找匹配的用户。如果找到匹配的用户,就会向目标用户发送WebSocket 信息。
- 接收并解析,触发动作
Bean模块接收到来自FastWeb的消息后,解析并触发模块窗体的 OnAjaxEvent
事件,事件的名称 eventname
以及 数据键值对 paramname=paramvalue
均由json定义。在 OnAjaxEvent
事件中可使用 params.Values["paramname"]
来读取键值对的数据信息。示例代码请参考 FastWeb 部分 接收并解析,触发动作
的代码。
# 4. 执行数据库查询(SQL)
在 FastWeb 中设置了数据库连接与预设 SQL 后,可利用 FastWeb 来执行 SQL 查询。发送的格式内容如下:
直接发送 SQL 语句:在 WebSocket 消息中可直接发送 SQL 语句来执行查询。示例如下(包含参数用法):
{
"action": "execsql",
"db_name": "demo",
"sql": "Insert Into Table_Test(FCode,FName) values(:F1,:F2)",
"params": [
{
"name": "F1",
"value": "003"
},
{
"name": "F2",
"value": "f37"
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
使用预设 SQL 执行查询:如在 预设 SQL 中设置了查询信息,可发送需查询的预设 SQL 来执行查询。创建一个名称为 SQL001
的预设 SQL,查询语句示例如下(包含参数用法):
Insert Into Table_Test(FCode,FName) values(:F1,:F2)
呼叫 WebSocket 执行数据库查询的文本示例如下:
{
"action": "execsql",
"db_name": "demo",
"sql_command_id": "SQL001",
"params": [
{
"name": "F1",
"value": "043"
},
{
"name": "F2",
"value": "d23"
}
]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15