wordpress 删除底部,云南专业网站优化,新媒体营销策略,3d建模自学教程websocket是什么
V-REP 中的 Web Socket 是一种用于在 V-REP 和外部应用程序之间进行通信的协议和技术。Web Socket 基于 TCP 连接#xff0c;可以提供双向、实时的数据传输#xff0c;适用于互动性或实时交互性应用。
(比如v-rep在云服务器上运行#xff0c;通过websocke…websocket是什么
V-REP 中的 Web Socket 是一种用于在 V-REP 和外部应用程序之间进行通信的协议和技术。Web Socket 基于 TCP 连接可以提供双向、实时的数据传输适用于互动性或实时交互性应用。
(比如v-rep在云服务器上运行通过websocket和用户所使用的web前端通信) 什么是云仿真
就是将v-rep的仿真程序发送到云服务器上借助云服务器更好的硬件设备更高效地运行v-rep程序用户可以从云服务器上获取需要的v-rep数据。
使用云仿真是将 V-REP 的仿真环境迁移到云端让 V-REP 在云服务器上进行运行用户通过互联网通过浏览器等远程接入云端的 V-REP环境来完成仿真操作。因此使用云仿真不需要将 V-REP 的程序发送到云服务器上运行而是将 V-REP 的仿真环境放到云端进行运行用户可以通过互联网访问云端的 V-REP 环境进行仿真任务而不需要在本地计算机上安装和配置 V-REP 软件。
什么是云端
云端Cloud指的是互联网上的远程服务器也被成为“云服务器”是封装计算资源的虚拟化环境。云端提供了一个集中式的存储、管理和运行数据和应用程序的平台用户可以通过互联网访问这些数据和应用程序。
《互联网上用于管理存储运行数据的服务器》 websocket在v-rep中的作用
完成云服务器上v-rep仿真和web浏览器之间的通信。
websocket的实现
v-rep内部websocket实现(服务端) wsRemoteAPI
源码链接
sim require sim
removeLazyLoaders()wsRemoteApi {}
//获取wsRemoteApi.verbose这个v-rep全局参数的值无值返回0
function wsRemoteApi.verbose()return sim.getNamedInt32Param(wsRemoteApi.verbose) or 0
endfunction wsRemoteApi.require(name)_G[name] require(name)
endfunction wsRemoteApi.info(obj)if type(obj) string then obj wsRemoteApi.getField(obj) endif type(obj) ~ table then return obj end
//~ :表示不等于local ret {}for k, v in pairs(obj) doif type(v) table thenret[k] wsRemoteApi.info(v)elseif type(v) function thenret[k] {func {}}elseif type(v) ~ function thenret[k] {const v}endendreturn ret
end
/*
该函数接受一个字符串类型的参数 f表示要获取的值的键。在 Lua 语言中字符串类似于表中的字段名可以作为表索引来访问对应的值。例如_G[print] 可以获取 Lua 语言中的 print 函数。在函数体内部首先将 _G 赋值给变量 v表示从全局变量表开始查找。然后通过 string.gmatch 函数循环遍历字符串类型的键 f 中所有的单词和下划线以及它们出现的顺序。在每次循环中根据单词获取表 v 中对应的值并将其赋值给变量 v。如果在遍历的过程中遇到了 v 为空nil的情况则说明字符串类型的键在 _G 全局变量表中不存在于是返回 nil。最后返回变量 v表示找到了对应的值并将其返回。
*/
//获取key(f)对应的value
function wsRemoteApi.getField(f)local v _Gfor w in string.gmatch(f, [%w_]) dov v[w]if not v then return nil endendreturn v
endfunction wsRemoteApi.handleRequest(req)if wsRemoteApi.verbose() 1 then print(request received:, req) endlocal resp {}resp[id] req[id]if req[func] ~ nil and req[func] ~ thenlocal func wsRemoteApi.getField(req[func])local args req[args] or {}if not func thenresp[error] No such function: .. req[func]elselocal status, retvals pcall(function()local ret {func(unpack(args))}return retend)resp[status and ret or error] retvalsendelseif req[eval] ~ nil and req[eval] ~ thenlocal status, retvals pcall(function()local ret {loadstring(return .. req[eval])()}return retend)resp[status and ret or error] retvalsendresp[success] resp[error] nilif wsRemoteApi.verbose() 1 then print(returning response:, resp) endreturn resp
endfunction onWSMessage(server, connection, message)local rawReq message-- if first byte is {, it *might* be a JSON payloadif rawReq:byte(1) 123 thenlocal req, ln, err json.decode(rawReq)if req ~ nil thenlocal resp wsRemoteApi.handleRequest(req)resp json.encode(resp)simWS.send(server, connection, resp, simWS.opcode.text)returnendend-- if we are here, it should be a CBOR payloadlocal status, req pcall(cbor.decode, rawReq)if status thenlocal resp wsRemoteApi.handleRequest(req)resp cbor.encode(resp)-- respsim.packTable(resp,1)simWS.send(server, connection, resp, simWS.opcode.binary)returnendsim.addLog(sim.verbosity_errors, cannot decode message: no suitable decoder)return
endfunction wsRemoteApi.publishStepCount()-- if wsRemoteApi.verbose()1 then-- print(publishing simulationTimeStepCount..simulationTimeStepCount)-- end
endfunction sysCall_info()return {autoStart sim.getNamedBoolParam(wsRemoteApi.autoStart) ~ false,menu Connectivity\nWebSocket remote API server,}
endfunction sysCall_init()simWS require simWSport sim.getNamedInt32Param(wsRemoteApi.port) or 23050if wsRemoteApi.verbose() 0 thensim.addLog(sim.verbosity_scriptinfos,string.format(WebSocket Remote API server starting (port%d)..., port))endjson require dkjson-- cborrequire cbor -- encodes strings as buffers, always. DO NOT USE!!cbor require org.conman.cborwsServer simWS.start(port)simWS.setMessageHandler(wsServer, onWSMessage)if wsRemoteApi.verbose() 0 thensim.addLog(sim.verbosity_scriptinfos, WebSocket Remote API server started)endstepping false
endfunction sysCall_cleanup()if not simWS then return endif wsServer then simWS.stop(wsServer) endif wsRemoteApi.verbose() 0 thensim.addLog(sim.verbosity_scriptinfos, WebSocket Remote API server stopped)end
endfunction sysCall_addOnScriptSuspend()return {cmd cleanup}
endfunction sysCall_addOnScriptSuspended()return {cmd cleanup}
endfunction sysCall_nonSimulation()
endfunction sysCall_beforeMainScript()local outDataif stepping thenoutData {doNotRunMainScript not go}go nilendreturn outData
endfunction sysCall_beforeSimulation()simulationTimeStepCount 0wsRemoteApi.publishStepCount()
endfunction sysCall_actuation()simulationTimeStepCount simulationTimeStepCount 1wsRemoteApi.publishStepCount()
endfunction sysCall_afterSimulation()stepping false -- auto disable sync. mode
endfunction setStepping(enable)stepping enablego nil
endfunction step()go true
end
wsRemoteAPI中的接口sysCall_init()调用simWS的start接口建立连接。
那么sysCall_init什么时候被执行呢
v-rep启动的时候就会自动启动连接的监听。 simWS
源码链接
从这个插件的start函数中可以看出调用startserver端就会listen,然后accept建立连接。 服务端代码启动流程
1监听启动
1-1v-rep启动----调用wsRemoteAPI中的接口sysCall_init()其中调用simWS的start接口监听建立连接。 2事件监听启动
onInstancePass中调用webSocket::server对象的poll接口进行事件监听。
onInstance由v-rep自动调用。 verbose
在 V-REP 中wsRemoteApi.verbose() 函数用于设置或获取远程 API 调用时的日志输出级别。日志输出级别是一个整数值决定了在进行远程 API 调用时打印哪些日志信息以便于调试和问题定位。
常见的远程 API 日志输出级别如下
- 0不输出任何信息 - 1输出仅关键信息如连接建立和断开等 - 2输出详细调用信息如函数名、参数等 - 3输出所有信息包括调试和错误信息。 浏览器前端websocket实现和接口调用(客户端)
前端怎么打开网页
html双击就会自动使用浏览器打开浏览器打开就会自动执行html。
(选择Edge浏览器快一些)
客户端代码启动流程
前端页面显示肯定是通过加载html文件通过解析html文件显示页面的。
前端通过在html中切入js语言浏览器自动解析并执行。 client端(前端)建立连接只需要两步
1建立RemoteAPIClient对象
2调用RemoteAPIClient中的WebSocketAsPromised对象的open接口发起连接。 前端html中的js建立RemoteAPIClient对象调用对象open()发起和server的连接利用这个对象---和服务端建立连接和通信。 scriptconst log (what) $(#log).append(${what}\n);(async () {var client new RemoteAPIClient(localhost, 23050, json);log(Connecting...);await client.websocket.open();log(Getting proxy object sim...);var sim await client.require(sim);log(Calling sim.getObject(/Floor)...);var [h] await sim.getObject(/Floor);log(Result: ${h});})();/script client端事件发送
RemoteAPIClient对象中的call接口调用WebScoketAsPromised对象的sendRequest接口发送数据并等待server端执行返回执行结果数据。 RemoteAPIClient
use strict;const WebSocketAsPromised require(websocket-as-promised);class RemoteAPIClient {//编解码方式默认为 cborconstructor(host localhost, port 23050, codec cbor, opts {}) {this.host host;this.port port;this.codec codec;var packMessage;var unpackMessage;/*则使用 CBOR 序列化和反序列化库 CBOR.encode 和 CBOR.decode进行编解码。packMessage 为一个函数将传入的数据进行 CBOR 编码并返回编码后的结果。unpackMessage 为一个异步函数将传入的数据进行 CBOR 解码并返回解码后的结果。如果编解码方式为 json则使用 JavaScript 原生的 JSON 序列化和反序列化函数 JSON.stringify 和 JSON.parse 进行编解码。*/if(this.codec cbor) {//this.websocket.binaryType arraybuffer;packMessage data CBOR.encode(data);unpackMessage async data CBOR.decode(await data.arrayBuffer());} else if(this.codec json) {packMessage data JSON.stringify(data);unpackMessage data JSON.parse(data);}var wsOpts {packMessage,unpackMessage,// attach requestId to message as id fieldattachRequestId: (data, requestId) Object.assign({id: requestId}, data),// read requestId from message id fieldextractRequestId: data data data.id,};for(var k in opts)wsOpts[k] opts[k];this.websocket new WebSocketAsPromised(ws://${this.host}:${this.port}, wsOpts);}
/*
使用 await 关键字等待该 Promise 对象执行完成并获取响应结果保存在变量reply 中。在该方法中使用了 async 关键字将 call 方法标记为异步函数使其返回一个 Promise 对象。在调用 await 时控制权会交给引擎等待 WebSocket 通信的异步操作完成并返回一个响应结果
*/
//函数调用传递函数名和参数async call(func, args) {var reply await this.websocket.sendRequest({func, args});if(reply.success) {return reply.ret;} else {throw reply.error;}}
/*
返回name所对应的值name可能是一个普通变量也可能是一个建值对的key,或者其他
js对象
*/async getObject(name) {var r await this.call(wsRemoteApi.info, [name]);return this.getObject_(name, r[0]);}async require(name) {await this.call(wsRemoteApi.require, [name]);return await this.getObject(name);}getObject_(name, _info) {const client this;var ret {}for(let k in _info) {var v _info[k];if(Object.keys(v).length 1 v[func] ! undefined)ret[k] async function(...args) {return await client.call(name . k, args);};else if(Object.keys(v).length 1 v[const] ! undefined)ret[k] v[const];elseret[k] this.getObject(name . k, null, null, v);}return ret}
}WebSocketAsPromised WebSocketAsPromised 是一个第三方 JavaScript 库用于实现基于 Promise 的 WebSocket 连接。 标准的 WebSocket API 使用回调函数来处理事件例如在连接建立时调用 onopen 回调函数在收到消息时调用 onmessage 回调函数等。而使用 WebSocketAsPromised 库可以直接返回 Promise 对象来处理 WebSocket 相关的操作这种写法更符合现代 JavaScript 中基于 Promise 或 async/await 的编程风格更易于编写和维护。 在这段代码中this.websocket 保存了一个 WebSocketAsPromised 类型的对象表示当前客户端的 WebSocket 连接。WebSocketAsPromised 的构造函数需要传递两个参数WebSocket 的 URL 和 WebSocket 配置对象。其中URL 参数表示要连接的 WebSocket 服务器的地址和端口号wsOpts 参数为可选参数对象用于配置 WebSocket 的一些选项如超时时间、心跳间隔等。 通过创建基于 Promise 的 WebSocketAsPromised 类型的对象可以使用 async/await 等方式来处理 WebSocket 连接的事件处理和错误处理让代码更加简洁、易读和可维护。
open()函数的作用
用于client对端发起连接和远程server建立连接。 scriptconst log (what) $(#log).append(${what}\n);(async () {var client new RemoteAPIClient(localhost, 23050, json);log(Connecting...);await client.websocket.open();log(Getting proxy object sim...);var sim await client.require(sim);log(Calling sim.getObject(/Floor)...);var [h] await sim.getObject(/Floor);log(Result: ${h});})();/script
如果open连接失败
如果open()连接失败open() 后面的代码不会执行而是会抛出异常。在这个案例中如果await client.websocket.open()连接失败控制台会输出一个错误或异常信息即不会输出Getting proxy object sim...或Result: ${h}。 这是因为await关键字会等待异步方法的执行结果如果异步方法出现错误或异常则会阻塞当前线程并将错误或异常抛出因此如果open()连接失败则异步 async () {...} 函数的执行会被中止后续的代码也不会执行。 对于上面的代码如果server端没打开client端一直处于Connecting
websocketpp
pp---cpp
websocket提供了封装好了client和server从链接建立数据监听通信到结束通信的对象和接口。
资料链接
讲解
用户手册 html和js
一般情况下前端加载 HTML 文件时其中的 JavaScript 代码就会被自动执行。这是因为 HTML 中的 script 标签会被浏览器自动解析并执行其中的 JavaScript 代码。 当浏览器解析 HTML 文件时碰到 script 标签时会自动执行其中的脚本。如果 script 标签中带有 src 属性则浏览器会根据该属性的值加载外部 JavaScript 文件并自动执行其中的代码。如果 script 标签内部有 JavaScript 代码则直接执行其中的代码。 需要注意的是当浏览器加载 JS 文件时会阻塞 HTML 页面的渲染。如果 JavaScript 代码很长或运行时间很长可能会导致页面出现卡顿的现象。为了避免这种情况可以将 JavaScript 代码放到页面底部在 HTML 元素加载完毕后再执行。另外也可以使用异步加载技术如 script async srcxxx.js/script 让 JS 文件在后台异步加载避免阻塞页面渲染。
eg:
!DOCTYPE html
htmlheadmeta charsetutf-8titleCoppeliaSim remote API client/title/headbodydiv idlog stylewhite-space: pre/divscript srchttps://code.jquery.com/jquery-3.6.0.min.js integritysha256-/xUj3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4 crossoriginanonymous/scriptscript srchttps://cdn.jsdelivr.net/gh/spaceify/cbor-jsmaster/cbor.js integritysha512-0ABB8mRQj73e8aaUzonPYnP34/YsUCf6SGUJp/pj5BUXttDonDIvCI7XuC7C27Qem6yRpzIzTlq8kJSlUNjoQ crossoriginanonymous/scriptscript srcWebSocketAsPromised.bundle.js/scriptscript srcRemoteAPIClient.js/scriptscriptconst log (what) $(#log).append(${what}\n);(async () {var client new RemoteAPIClient(localhost, 23050, json);log(Connecting...);await client.websocket.open();log(Getting proxy object sim...);var sim await client.require(sim);log(Calling sim.getObject(/Floor)...);var [h] await sim.getObject(/Floor);log(Result: ${h});})();/script/body
/html这是一个基于 JavaScript 的 V-REP 远程 API 客户端示例用于在网页中通过 JavaScript 调用 V-REP 中的场景对象和函数。 在代码中首先定义了一个 log 函数用于在页面上输出调试信息。然后使用 async 函数和箭头函数等语法定义了一个立即执行的异步函数其中包含了调用 V-REP 远程 API 的过程。 在异步函数中首先创建了一个名为 client 的 RemoteAPIClient 对象用于与 V-REP 中的远程 API 服务建立连接。其中 localhost 表示连接本地计算机23050 表示连接的端口号json 表示使用 JSON-RPC 协议进行通信。 然后使用 client.require(sim) 函数获取到远程 API 的命名空间 sim该命名空间包含了 V-REP 中预定义的各种对象和函数。最后使用 sim.getObject(/Floor) 函数获取到名为 /Floor 的场景对象将结果保存到变量 h 中。 在获取到结果后调用 log 函数将结果输出到页面上。 js调用加载lua模块调用lua接口实现及原理
最终的实现是通过三方库定义的WebSocketAsPromised接口sendRequest()向服务端发送需要调用的接口和参数服务端接收到请求之后会执行需要调用的接口并返回执行接口返回的内容。
因为我们v-rep中的RemoteAPIClient指定了序列化和反序列化所以即使调用Lua或者c接口反序列化之后就可以变为js所对应的数据。
class RemoteAPIClient {//编解码方式默认为 cborconstructor(host localhost, port 23050, codec cbor, opts {}) {this.host host;this.port port;this.codec codec;var packMessage;var unpackMessage;/*则使用 CBOR 序列化和反序列化库 CBOR.encode 和 CBOR.decode进行编解码。packMessage 为一个函数将传入的数据进行 CBOR 编码并返回编码后的结果。unpackMessage 为一个异步函数将传入的数据进行 CBOR 解码并返回解码后的结果。如果编解码方式为 json则使用 JavaScript 原生的 JSON 序列化和反序列化函数 JSON.stringify 和 JSON.parse 进行编解码。数据传输格式使用json无论数据来自lua函数返回还是c函数返回JSON.parse都解析为js数据。*/if(this.codec cbor) {//this.websocket.binaryType arraybuffer;packMessage data CBOR.encode(data);unpackMessage async data CBOR.decode(await data.arrayBuffer());} else if(this.codec json) {packMessage data JSON.stringify(data);unpackMessage data JSON.parse(data);}var wsOpts {packMessage,unpackMessage,// attach requestId to message as id fieldattachRequestId: (data, requestId) Object.assign({id: requestId}, data),// read requestId from message id fieldextractRequestId: data data data.id,};for(var k in opts)wsOpts[k] opts[k];this.websocket new WebSocketAsPromised(ws://${this.host}:${this.port}, wsOpts);} 客户端怎么调用接口的
通过html中执行js代码。
方式1先加载模块再通过模块加载模块中定义的接口。 插件中的返回值通过js获取
直接在js中定义与调用的函数返回的类型对应的js变量接收返回值即可。 //getInfo返回数组var [info]await simTest.getInfo();log(info length: ${info.length});for(var i0;iinfo.length;i){log(getInfo: ${info[i]});}