当前位置: 首页 > news >正文

skynet 使用protobuf

一、安装protobuf

    下面的操作方法都是在 centos 环境下操作

#下载 Protocol Buffers 源代码:
#您可以从 Protocol Buffers 的 GitHub 仓库中获取特定版本的源代码。使用以下命令克隆仓库
git clone -b v3.20.3 https://github.com/protocolbuffers/protobuf.git#编译和安装:
#进入克隆的目录,然后编译和安装 Protocol Buffers:
cd protobuf
./autogen.sh
./configure
make
sudo make install#验证安装:
protoc --version#您应该看到输出,指示安装的版本为 3.20.3。

二、安装pdb库

#第三方库安装在3rd目录下
cd skynet/3rd/
git clone https://github.com/cloudwu/pbc.gitcd pbc
make#编译成功后,打开skynet/3rd/pbc/binding/lua53/Makefile文件,修改里面的lua路径
CC = gccCFLAGS = -O2 -fPIC -WallLUADIR = ../../../lua   #这个路劲就是skynet/3rd/luaTARGET = protobuf.so.PHONY : all cleanall : $(TARGET)$(TARGET) : pbc-lua53.c$(CC) $(CFLAGS) -shared -o $@ -I../.. -I$(LUADIR) -L../../build $^ -lpbcclean :rm -f $(TARGET)#去到lua53目录,编译生成protobuf.so库
cd ./binding/lua53
sudo make

三、将依赖文件放到工程目录下

   将 protobuf.so 和 protobuf.lua 分别放入 luaclib 、lualib

cp protobuf.so ../../../../luaclib/  #将protobuf.so复制到存放C模块的lualib目录中    
cp protobuf.lua ../../../../lualib/  #将protobuf.lua复制到存放Lua模块的lualib目录中

四、创建protobuf目录

在skynet目录下创建protobuf目录,用来存放原始 .proto 描述文件

  这里举例 login.proto

mkdir protobuflogin.proto的内容如下代码所示:
syntax = "proto3";  
package Login;message login {string account=1;string passwd=2;int32 result=3;
}

五、编译proto文件

protoc --descriptor_set_out login.pb login.proto

   这里写了个gen_pb.sh脚本,将protobuf目录下的所有.sproto文件转成proto文件

#!/bin/bash  # 指定要遍历的目录,这里使用当前目录"."  
dir="."  # 使用find命令查找所有.proto文件,并调用basename和cut命令来截取文件名  
find "$dir" -type f -name "*.proto" | while read -r filepath; do  # 使用basename命令获取文件名部分,然后使用cut命令去除后缀  filename=$(basename "$filepath")  filename_without_extension="${filename%.*}"  # 输出截取后的文件名  echo "$filename, $filename_without_extension"  # 在这里可以添加其他操作,比如使用protoc编译等  protoc --descriptor_set_out "$filename_without_extension.pb" "$filename" 
done

六、了解protobuf.lua 关键函数

1、 protobuf.register

  • 功能:注册 Protobuf 
  • 参数:buffer  .pb文件读取出来的二进制字符串
  • 返回值:无。
function M.register(buffer)c._env_register(P, buffer) 
end

   备注: register需要自己去加载.pb文件内容,下面的register_file函数使用会更多

2、protobuf.register_file

  • 功能:注册 Protobuf 
  • 参数:filename 为  .pb文件名。  
  • 返回值:无。
function M.register_file(filename)local f = assert(io.open(filename , "rb"))local buffer = f:read "*a"c._env_register(P, buffer)f:close()
end

3、protobof.encode

  • 功能:将一个 Lua 表编码为 Protobuf 格式的二进制消息。
  • 参数:message 是注册的 Protobuf 定义的名称,msg 是要编码的 Lua 表。
  • 返回值:编码后的二进制数据。

function M.encode( message, t , func , ...)local encoder = c._wmessage_new(P, message)assert(encoder ,  message)encode_message(encoder, message, t)if func thenlocal buffer, len = c._wmessage_buffer(encoder)local ret = func(buffer, len, ...)c._wmessage_delete(encoder)return retelse    local s = c._wmessage_buffer_string(encoder)c._wmessage_delete(encoder)return send
end

4、protobof.decode

  • 功能:将一个 Protobuf 编码的二进制消息解码为 Lua 表。
  • 参数:typename 是注册的 Protobuf 定义的名称,buf 是包含 Protobuf 编码消息的二进制数据。
  • 返回值:解码后的 Lua 表。

function M.decode(typename, buffer, length)local ret = {}local ok = c._decode(P, decode_message_cb , ret , typename, buffer, length)if ok thenreturn setmetatable(ret , default_table(typename))elsereturn false , c._last_error(P)end
end

七、protobuf测试用例

   在examples 目录下新建 test_protobuf.lua 

package.path = package.path .. ";./lualib/?.lua"
package.cpath = package.cpath .. ";./luaclib/?.so"local protobuf = require "protobuf"      --引入文件protobuf.lua
protobuf.register_file "./protobuf/common.pb" --注册pb文件
protobuf.register_file "./protobuf/login.pb" --注册pb文件local loginInfo = { account = "test", passwd = "pw"} local encodeData = protobuf.encode("Login.login", loginInfo)
print("encodeData:", encodeData)local decodeData = protobuf.decode("Login.login", encodeData)
print("decodeData account:", decodeData.account)
print("decodeData passwd:", decodeData.passwd)

八、skynet 使用protobuf进行网络通信

1、 将数据打包成二进制数据

--[[big endianhead    2 byte body size2 byte protonamesizen byte protonamebody    n byte data@desc: 将lua格式的协议序列化为二进制数据
]] 
function protobufDataHelper.encode( name,data )local stringbuffer =  protobuf.encode(name, data)         -- protobuf序列化 返回lua stringlocal body = string.pack(">s2s",name,stringbuffer)       -- 打包包体 协议名 + 协议数据local head = string.pack(">I2",#body)                     -- 打包包体长度print("encode proto_name:", name, ",data_size:", #body, ",totalSize:", #head+#body)return head .. body                                       -- 包体长度 + 协议名 + 协议数据
end

2、将二进制数据解包

--[[@desc: 将二进制数据反序列化为lua string--@msg: C Point @return:协议名字,协议数据
]]
function protobufDataHelper.decode( msg  )--- 前两个字节在netpack.filter 已经解析print("msg size:", #msg)local proto_name,stringbuffer = string.unpack(">s2s",msg)print("proto_name", proto_name, "data:", stringbuffer)local body = protobuf.decode(proto_name, stringbuffer)return proto_name,body
end

3、skyent unpack类型指定为二进制字符串

     这里在agent.lua 注册消息协议类型时处理

skynet.register_protocol {name = "client",id = skynet.PTYPE_CLIENT,   unpack = skynet.tostring,   --- 将C point 转换为lua 二进制字符串
}

  在dispatch_message消息地方反序列化消息

--- 分发消息
local function  dispatch_message(msg)--- 反序列化二进制string数据local pack_name,data = dataHelper.decode(msg)     --   pack_name = c2s.testlocal sub_name = pack_name:match(".+%.(%w+)$")    --   sub_name = test......local f = REQUEST[sub_name]if f == nil thenprint("not function define handle package:", pack_name)returnendf(data)
end

agent.lua 改造测试代码如下

local skynet = require "skynet"
local socket = require "skynet.socket"
local sproto = require "sproto"
local sprotoloader = require "sprotoloader"
local login = require "login"
local tableutil = require "tableutil"local dataHelper = require "protobufDataHelper"local WATCHDOG
local host
local send_requestlocal CMD = {}
local REQUEST = {}
local client_fdfunction REQUEST:get()print("get", self.what)local r = skynet.call("SIMPLEDB", "lua", "get", self.what)return { result = r }
endfunction REQUEST:set()print("set", self.what, self.value)local r = skynet.call("SIMPLEDB", "lua", "set", self.what, self.value)
endfunction REQUEST:handshake()return { msg = "Welcome to skynet, I will send heartbeat every 5 sec." }
endfunction REQUEST:quit()skynet.call(WATCHDOG, "lua", "close", client_fd)
endlocal function send_data(name, args)local data = dataHelper.encode(name, args)-- 发送数据socket.write(client_fd,data)
endfunction REQUEST:login()print("login account,passwd:", self.account, self.passwd)local result = login.loginRequest(self.account, self.passwd)if result ~= 0 thenprint("kill client, client_fd:", client_fd)REQUEST:quit()endlocal loginInfo = { account = "kk", passwd = "haha"}send_data("Login.login", loginInfo)return {result = result}
endfunction REQUEST:loginTest()print("loginTest:", tableutil.tPrint(self))
endlocal function request(name, args, response)local f = assert(REQUEST[name])print("recieve request, protoName:", name, tableutil.tPrint(args))local r = f(args)if response thenreturn response(r)end
endlocal function send_package(pack)local package = string.pack(">s2", pack)socket.write(client_fd, package)
end--[[
skynet.register_protocol {name = "client",id = skynet.PTYPE_CLIENT,unpack = function (msg, sz)return host:dispatch(msg, sz)end,dispatch = function (fd, _, type, ...)assert(fd == client_fd)	-- You can use fd to reply messageskynet.ignoreret()	-- session is fd, don't call skynet.retskynet.trace()if type == "REQUEST" thenlocal ok, result  = pcall(request, ...)if ok thenif result thensend_package(result)endelseskynet.error(result)endelseassert(type == "RESPONSE")error "This example doesn't support request client"endend
}--]]skynet.register_protocol {name = "client",id = skynet.PTYPE_CLIENT,	unpack = skynet.tostring,   --- 将C point 转换为lua 二进制字符串
}function CMD.start(conf)local fd = conf.clientlocal gate = conf.gateWATCHDOG = conf.watchdog-- slot 1,2 set at main.luahost = sprotoloader.load(1):host "package"send_request = host:attach(sprotoloader.load(2))skynet.fork(function()local index = 1while true do--send_package(send_request "heartbeat")index = index + 1local loginInfo = { account = "kk"..index, passwd = "haha"}send_data("Login.login", loginInfo)skynet.sleep(500)endend)client_fd = fdskynet.call(gate, "lua", "forward", fd)
endfunction CMD.disconnect()-- todo: do something before exitskynet.exit()
end--- 分发消息
local function  dispatch_message(msg)--- 反序列化二进制string数据local pack_name,data = dataHelper.decode(msg)     --   pack_name = c2s.testlocal sub_name = pack_name:match(".+%.(%w+)$")    --   sub_name = testprint("recieve request, protoName:", pack_name, tableutil.tPrint(data))local f = REQUEST[sub_name]if f == nil thenprint("not function define handle package:", pack_name)returnendf(data)
endskynet.start(function()skynet.dispatch("lua", function(_,_, command, ...)skynet.trace()local f = CMD[command]skynet.ret(skynet.pack(f(...)))end)skynet.dispatch("client", function (session, address, msg)dispatch_message(msg)end)
end)

4、客户端测试代码

client_protobuf.lua

package.cpath = "luaclib/?.so;skynet/luaclib/?.so"
package.path = "lualib/common/?.lua;lualib/?.lua;skynet/lualib/?.lua;skynet/examples/?.lua"local tableutil = require "tableutil"if _VERSION ~= "Lua 5.4" thenerror "Use lua 5.4"
endlocal socket = require "client.socket"
local dataHelper = require "protobufDataHelper"local fd = assert(socket.connect("127.0.0.1", 8888))local function send_data(name, args)local data = dataHelper.encode(name, args)-- 发送数据socket.send(fd,data)
endlocal loginInfo = { account = "test", passwd = "haha"}
send_data("Login.login", loginInfo)
send_data("Common.heartbeat", {})local function unpack_package(text)local size = #textif size < 2 thenreturn nil, textendlocal s = text:byte(1) * 256 + text:byte(2)if size < s+2 thenreturn nil, textendreturn text:sub(3,2+s), text:sub(3+s)
endlocal function recv_package(last)local resultresult, last = unpack_package(last)if result thenreturn result, lastendlocal r = socket.recv(fd)if not r thenreturn nil, lastendif r == "" thenerror "Server closed"endreturn unpack_package(last .. r)
endlocal last = ""
local function dispatch_package()while true dolocal vv, last = recv_package(last)if not v thenbreakendlocal packName, data = dataHelper.decode(v)print("packName:", packName)print("data:", tableutil.tPrint(data) )end
endwhile true dodispatch_package()socket.usleep(1000000)
end

相关文章:

skynet 使用protobuf

一、安装protobuf 下面的操作方法都是在 centos 环境下操作 #下载 Protocol Buffers 源代码&#xff1a; #您可以从 Protocol Buffers 的 GitHub 仓库中获取特定版本的源代码。使用以下命令克隆仓库 git clone -b v3.20.3 https://github.com/protocolbuffers/protobuf.git#编译…...

Vue Router 4 与 Router 3 路由配置与区别

文章目录 路由安装路由配置vue-router 3.x版本写法配置路由使用路由 vue-router 4.x版本写法配置路由使用路由 Vue Router 4 与 Vue Router 3 区别 路由安装 Vue 2 (使用 Vue Router 3) &#xff1a;npm install vue-router3 Vue 3 (使用 Vue Router 4) &#xff1a;npm insta…...

python借助elasticsearch实现标签匹配计数

给定一组标签 [{“tag_id”: “1”, “value”: “西瓜”}, {“tag_id”: “1”, “value”: “苹果”}]&#xff0c;我想精准匹配到现有的标签库中存在的标签并记录匹配成功的数量。 标签id(tag_id)标签名(tag_name)标签值(tag_name )1水果西瓜1水果苹果1水果橙子2动物老虎 …...

Yolo-world+Python-OpenCV之摄像头视频实时目标检测

上一次介绍了如何使用最基本的 Yolo-word来做检测&#xff0c;现在我们在加opencv来做个实时检测的例子 基本思路 1、读取离线视频流 2、将视频帧给yolo识别 3、根据识别结果 对视频进行绘制边框、加文字之类的 完整代码如下&#xff1a; import datetimefrom ultralytics …...

vue-treeselect 的基本使用

vue-treeselect 的基本使用 1. 效果展示2. 安装 插件3. 引入组件4. 代码 1. 效果展示 2. 安装 插件 vue-treeselect是一个树形的下拉菜单&#xff0c;至于到底有多少节点那就要看你的数据源有多少层了&#xff0c;挺方便的。下面这个这个不用多说吧&#xff0c;下载依赖 npm in…...

Vue(二)

文章目录 1.条件渲染1.关于js中的false的判定2.基本介绍3.v-if1.需求分析2.代码实例 4.v-show实现5.v-if与v-show比较6.课后练习 2.列表渲染1.代码实例2.课后练习 3.组件化编程1.基本介绍2.实现方式一_普通方式2.实现方式二_全局组件方式3.实现方式三_局部组件方式 4.生命周期和…...

Python基于深度学习的车辆特征分析系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…...

推理还原的干货

故事的递进还原 从下层故事到上层故事 设定还原 还原的逻辑 隐藏信息拼凑、因果导致果推因、规则还原现象 设计思路&#xff1a; 真解答 真解答的关键信息 推理逻辑链 哪些环节可以被误导 如何把关键信息变成伪解答 解释变形信息 给出识别变形信息的方法或线索 其实看似一个…...

【Redis 神秘大陆】006 灾备方案

六、Redis 灾备方案 6.1 存储方案 6.1.1 基础对比 RDB持久化AOF持久化原理周期性fork子进程生成持久化文件每次写入记录命令日志文件类型二进制dump快照文件文本appendonly日志文件触发条件默认超过300s间隔且有1s内超过1kb数据变更永久性每秒fsync一次文件位置配置文件中指…...

【Java基础】17.异常处理

文章目录 前言一、异常的概念1.异常的3种类型2.支持异常处理的关键字和类 二、Exception 类的层次三、内置异常类1.非检查性异常2.检查性异常类 四、异常处理1.捕获异常2.多重捕获块3.throws/throw 关键字1.throw 关键字2.throws 关键字 3.finally关键字 五、编译时异常处理方式…...

【python】flask结合SQLAlchemy,在视图函数中实现对数据库的增删改查

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…...

APIGateway的认证

APIGateway的支持的认证如下&#xff1a; 我们从表格中可以看到&#xff0c;HTTP API 不支持资源策略的功能&#xff0c;另外是通过JWT的方式集成Cognito的。 对于REST API则是没有显示说明支持JWT认证&#xff0c;这个我们可以通过Lambda 自定义的方式来实现。 所以按照这个…...

MacOS Github Push项目 精简版步骤

大白菜教程&#xff1a;小白菜 macOS github提交代码-CSDN博客 步骤1&#xff1a;git init步骤2&#xff1a; touch .gitignore 创建ignore文件 open .gitignore 打开ignore文件 编写ignore文件.idea/ 是文件夹的意思.git/ 也是自动生成的文件夹 也不上传.DS_St…...

Eclipse的基本使用讲解(建项目,建包,建类,写代码(基本语法))新手入门必备

目录 一.介绍eclipse 二.操作Eclipse 1.选择工作空间 2.建项目&#xff0c;建包&#xff0c;建类 1.建项目(两种) 2.建包 3.建类 三.写代码(基本语法) 1.代码操作 2.代码规范 3.代码注释 一.介绍eclipse Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其…...

3D模型处理的并行化

今天我们将讨论如何使用 Python 多进程来处理大量3D数据。 我将讲述一些可能在手册中找到的一般信息&#xff0c;并分享我发现的一些小技巧&#xff0c;例如将 tqdm 与多处理 imap 结合使用以及并行处理存档。 那么我们为什么要诉诸并行计算呢&#xff1f; 使用数据有时会出现…...

盲人安全导航技巧:科技赋能让出行更自如

作为一名资深记者&#xff0c;长期关注并报道无障碍领域的发展动态。今日&#xff0c;我将聚焦盲人安全导航技巧&#xff0c;探讨这一主题下科技如何赋能视障人士实现更为安全、独立的出行。一款融合了实时避障、拍照识别物体及场景功能的盲人出行辅助应用叫做蝙蝠避障&#xf…...

问,由于java存在性能上,以及部分功能上的缺点,请问如何正确使用C,C++,Go,这三个语言,提升Java Web项目的性能?

拓展阅读&#xff1a;版本任你发&#xff0c;我用java8 我明白Java虽然在许多方面表现出色&#xff0c;但在某些特定场景下可能会遇到性能瓶颈或功能限制。为了提升Java Web项目的性能&#xff0c;可以考虑将C、C和Go这三种语言用于特定的组件或服务。以下是如何正确使用这些语…...

【信号与系统 - 9】傅里叶变换的性质习题

1 习题 已知 f ( t ) f(t) f(t) 的傅里叶变换为 F ( j w ) F(jw) F(jw) &#xff0c;求如下信号的傅里叶变换 &#xff08;1&#xff09; t ⋅ f ( 3 t ) t\cdot f(3t) t⋅f(3t) 解&#xff1a; f ( 3 t ) ↔ 1 3 F ( j w 3 ) f(3t)\leftrightarrow \frac{1}{3}F(j\frac{w}…...

C#探索之路基础夯实篇(5):语法糖概念解析

C#探索之路基础夯实篇(5)&#xff1a;语法糖概念解析 文章目录 C#探索之路基础夯实篇(5)&#xff1a;语法糖概念解析1、概念定义2、Lua中的语法糖3、C#中的语法糖4、C中的语法糖5、优缺点辨析6、适用范围7、总结 从之前一开始接触lua的时候开始&#xff0c;开始第一次接触到语法…...

SeaTunnel 与 DataX 、Sqoop、Flume、Flink CDC 对比

产品概述 Apache SeaTunnel 是一个非常易用的超高性能分布式数据集成产品,支持海量数据的离线及实时同步。每天可稳定高效同步万亿级数据,已应用于数百家企业生产,也是首个由国人主导贡献到 Apache 基金会的数据集成顶级项目。 SeaTunnel 主要解决数据集成领域的常见问题:…...

深入理解汇编:平栈、CALL和RET指令详解

​视频学习下载地址&#xff1a;​​https://pan.quark.cn/s/04e6946a803a​​ 汇编语言以其接近硬件的特性和高效的执行速度&#xff0c;在系统编程、性能优化和逆向工程中占有不可或缺的地位。本文将深入探讨汇编语言中的平栈操作以及​​CALL​​​和​​RET​​指令&#…...

DP4 最小花费爬楼梯

原题链接&#xff1a;最小花费爬楼梯_牛客题霸_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 dp。 开一个dp数组和a数组。dp[i]表示在当前这一格所需要的费用&#xff0c;a数组其实就是题目中的cost数组。 因为最后要求到顶楼的最低费用&a…...

OpenXR API概览与核心组件解析

在虚拟现实&#xff08;VR&#xff09;和增强现实&#xff08;AR&#xff09;领域&#xff0c;OpenXR API提供了一个重要的开放标准&#xff0c;使得开发者能够跨多种硬件和软件平台创建兼容的应用。本文将详细解释OpenXR中的核心组件和数据结构&#xff0c;并探讨它们如何共同…...

安装指定版本的ant-design-vue和指定版本的@ant-design/icons-vue 图标组件包

前言&#xff1a; 最近在完成公司的项目时&#xff0c;为了兼容其他的版本&#xff0c;需要安装指定版本的ant-design-vue和ant-design/icons-vue 图标组件包&#xff0c;安装成功之后&#xff0c;分享如下&#xff1a; 安装命令&#xff1a; ant-design-vue&#xff1a; 不…...

Zynq7000系列中的休眠模式

休眠模式是在系统层面定义的&#xff0c;它包括将APU置于待机模式&#xff0c;并将多个控制器保持在无时钟的复位状态。 进入休眠模式可以大大降低功耗。在休眠模式下&#xff0c;大多数功能时钟组都会被关闭或断电。唯一需要保持活动的设备是一个CPU、窥探控制单元&#xff08…...

在redhat7/8平台上部署ELK7.17.18的技术方案

部署环境说明 为节省资源直接使用1台测试机模拟3节点elasticsearch服务集群做部署&#xff0c;在该主机上同时部署了3个elasticsearch实例、1个logstash实例、1个kibana实例、1个filebeat实例。对于生产环境&#xff0c;以上实例服务应该做分布式部署。 ELK-TEST1 192.168.10…...

(Chat For Al,创新Al,汇语Al助手,AiTab新标签,万能助手,LLaVA)分享6个好用的ChatGPT

目录 1、Chat For AI 2、创想AI 3、汇语AL助手...

MySQL-锁篇

文章目录 表级锁和行级锁了解吗&#xff1f;有什么区别&#xff1f;行级锁使用有什么注意事项&#xff1f;InnoDB有哪几类行锁&#xff1f;共享锁和排他锁是什么&#xff1f;意向锁有什么用&#xff1f; 锁是一种常见的并发事务的控制方式 表级锁和行级锁了解吗&#xff1f;有什…...

滤波器笔记(杂乱)

线性相位是时间平移&#xff0c;相位不失真 零、基础知识 1、用相量表示正弦量 https://zhuanlan.zhihu.com/p/345546880 https://www.zhihu.com/question/347763932/answer/1103938667 A s i n ( ω t θ ) ⇔ A e j θ ⇔ A ∠ θ Asin(\omega t\theta) {\Leftrightarrow…...

【ARFoundation自学01】搭建AR框架,检测平面点击位置克隆物体

Unity开发ARFoundation相关应用首先安装ARFoundation包 然后设置XR 1.基础AR场景框架搭建 2.一个基本的点击克隆物体到识别的平面脚本 挂在XROrigin上 脚本AppController 脚本说明书 ## 业务逻辑 AppController 脚本旨在实现一个基本的 AR 应用程序功能&#xff1a;用户通过…...

源码论坛网站/环球军事网最新军事新闻最新消息

1. 查看当前使用的内核版本 uname -a 2.在终端下察看已经安装的旧的内核&#xff1a; ctrlaltt——>进入终端——>输入命令&#xff1a; dpkg --get-selections|grep linux 可以看到都是一些内核启动文件&#xff0c;很明显有些是我们不需要的&#xff08;建议先卸载比较…...

自己做的网站怎么在百度搜索到/营销活动怎么做吸引人

该方法是绑定在jQuery.prototype上的一个静态方法&#xff0c;目的是取出jQuery对象中的某个或全部DOM元素。 使用方法&#xff1a; $("someDOM").get(index); 此时会获取到$("someDOM")这个jQuery对象中第index个DOM元素。 源码&#xff1a; get: functio…...

做家教网站怎么样/推广方案框架

2019独角兽企业重金招聘Python工程师标准>>> WAF&#xff0c;主要是对Web特有入侵方式的加强防护&#xff0c;如DDOS防护、SQL注入、XML注入、XSS等。由于是应用层而非网络层的入侵&#xff0c;从技术角度都应该称为Web IPS&#xff0c;而不是Web防火墙。由于重点是…...

做网站建设的前景/seo博客优化

基础知识 1) 什么是”Last-Modified”? 在浏览器第一次请求web资源时&#xff0c;服务器端的返回状态会是200&#xff0c;内容是你请求的资源&#xff0c;同时有一个Last-Modified的属性标记此资源在服务期端最后被修改的时间&#xff0c;格式类似这样&#xff1a; …...

深圳便宜网站建设/青岛seo杭州厂商

干互联网这一行&#xff0c;你得保持终身学习的习惯&#xff0c;不断开拓视野&#xff0c;提升自我格局&#xff0c;比如一些优质公众号就是一个很不错的学习来源&#xff0c;我从关注的近千个公众号中挑选了一些优质原创技术号&#xff0c;推荐给大家。这些号一般是由深耕技术…...

frontpage怎样做网站/seo营销课程培训

转自&#xff1a;https://www.xuebuyuan.com/934357.html 需要引入standard.jar和jstl.jar 正确添加即可...