Hyperledger Fabric 管理链码 peer lifecycle chaincode 指令使用
Hyperledger Fabric 管理链码 peer lifecycle chaincode 指令使用
链上代码(Chaincode)简称链码,包括系统链码和用户链码。系统链码(System Chaincode)指的是Fabric Peer中负责系统配置、查询、背书、验证等平台功能的代码逻辑,运行在Peer进程内,将在第14章介绍。用户链码指的是用户编写的用来实现智能合约的应用代码。如无特殊说明,链码一般指的就是用户链码。
链码被部署在Peer节点上,运行在独立的沙盒(目前为Docker容器)中,并通过gRPC协议与相应的Peer节点进行交互。用户可以通过命令行或SDK调用链码方法,链码被调用时,会按照链码内预定逻辑来计算账本状态的更新集合(读写集合)。
链码操作命令
Operate a chaincode: install|instantiate|invoke|package|query|signpackage|upgrade|list.Usage:peer chaincode [command]Available Commands:install Install a chaincode.instantiate Deploy the specified chaincode to the network.invoke Invoke the specified chaincode.list Get the instantiated chaincodes on a channel or installed chaincodes on a peer.package Package a chaincodequery Query using the specified chaincode.signpackage Sign the specified chaincode packageupgrade Upgrade chaincode.Flags:--cafile string Path to file containing PEM-encoded trusted certificate(s) for the ordering endpoint--certfile string Path to file containing PEM-encoded X509 public key to use for mutual TLS communication with the orderer endpoint--clientauth Use mutual TLS when communicating with the orderer endpoint--connTimeout duration Timeout for client to connect (default 3s)-h, --help help for chaincode--keyfile string Path to file containing PEM-encoded private key to use for mutual TLS communication with the orderer endpoint-o, --orderer string Ordering service endpoint--ordererTLSHostnameOverride string The hostname override to use when validating the TLS connection to the orderer--tls Use TLS when communicating with the orderer endpoint--tlsHandshakeTimeShift duration The amount of time to shift backwards for certificate expiration checks during TLS handshakes with the orderer endpoint--transient string Transient map of arguments in JSON encodingUse "peer chaincode [command] --help" for more information about a command.
最简单的操作链码的方式是使用命令行。Fabric自2.0版本开始正式启用新的生命周期系统链码(位于core/chaincode/lifecycle)来管理链码(需开启应用能力V2_0),客户端通过新的 peer lifecycle chaincode
子命令(位于internal/peer/lifecycle)对链码进行打包、安装、批注和提交等生命周期管理,取代1.x中的 peer chaincode
命令。
相对1.x版本中的模式,新的链码管理从单个组织升级为通道范畴。例如,链码的背书策略可由通道内多个组织来商定,部署和升级也作为通道层面的操作,这些都提高了链码生命周期的安全性。如果要对链码进行调用或查询,仍可以使用原有的peer chaincode invoke
和 peer chaincode query
命令。
如果要使用1.x版本中的链码生命周期管理(peer chaincodeinstall/instantaite/upgrade/list等命令),需要将通道的应用能力版本设置为兼容的低版本,如V1_4_2。当通道启用了应用能力V2_0后,将无法再部署或升级原有模式下的链码。
链码生命周期:
链码操作支持全局命令选项:
全局选项 | 类型 | 含义 |
---|---|---|
--cafile | string | 信任的排序服务的 TLS CA 的证书(PEM编码格式)路径 |
--certfile | string | 与排序服务进行双向 TLS 认证时使用的本地证书文件路径 |
--clientauth | bool | 与排序服务通信时是否启用双向 TLS 认证 |
--connTimeout | duration | 客户端连接超时,默认为 3 秒 |
--keyfile | string | 与排序服务双向 TLS 认证时使用的本地私钥文件路径 |
-o,--orderer | string | Orderer 服务地址 |
--ordererTLSHostnameOverride | string | 验证 Orderer TLS 时覆盖所校验的主机名 |
--tls | bool | 连接到 Orderer 服务时是否启用 TLS |
--transient | string | 调用链码时传递的临时信息,其他 peer 将无法获取该信息 |
打包链码
package
子命令可以封装链码相关的数据,将其打包为.tar.gz安装包,供安装使用。
Package a chaincode and write the package to a file.Usage:peer chaincode package [outputfile] [flags]Flags:-s, --cc-package create CC deployment spec for owner endorsements instead of raw CC deployment spec-c, --ctor string Constructor message for the chaincode in JSON format (default "{}")-h, --help help for package-i, --instantiate-policy string instantiation policy for the chaincode-l, --lang string Language the chaincode is written in (default "golang")-n, --name string Name of the chaincode-p, --path string Path to chaincode-S, --sign if creating CC deployment spec package for owner endorsements, also sign it with local MSP-v, --version string Version of the chaincode specified in install/instantiate/upgrade commandsGlobal Flags:--cafile string Path to file containing PEM-encoded trusted certificate(s) for the ordering endpoint--certfile string Path to file containing PEM-encoded X509 public key to use for mutual TLS communication with the orderer endpoint--clientauth Use mutual TLS when communicating with the orderer endpoint--connTimeout duration Timeout for client to connect (default 3s)--keyfile string Path to file containing PEM-encoded private key to use for mutual TLS communication with the orderer endpoint-o, --orderer string Ordering service endpoint--ordererTLSHostnameOverride string The hostname override to use when validating the TLS connection to the orderer--tls Use TLS when communicating with the orderer endpoint--tlsHandshakeTimeShift duration The amount of time to shift backwards for certificate expiration checks during TLS handshakes with the orderer endpoint--transient string Transient map of arguments in JSON encoding
其中,生成的打包文件中包括Chaincode-Package-Metadata.json、Code-Package.tar.gz两个文件。Chaincode-Package-Metadata.json内容包括链码路径、类型、标签等信息.Code-Package.tar.gz内容包括链码的源码包结构,如src/examples/chaincode/go/testcc/路径以及内容,但不能包括对目录以外路径的引用。
注意:自2.0版本起,编译链码的ccenv镜像不再包括shim层。链码需要自行包括github.com/hyperledger/fabric-chaincode-go/shim和其他所需要的依赖包。
安装链码
打包后的链码安装包文件,可以使用install命令安装到运行链码的各个Peer。
Install a chaincode on a peer. This installs a chaincode deployment spec package (if provided) or packages the specified chaincode before subsequently installing it.Usage:peer chaincode install [flags]Flags:--connectionProfile string Connection profile that provides the necessary connection information for the network. Note: currently only supported for providing peer connection information-c, --ctor string Constructor message for the chaincode in JSON format (default "{}")-h, --help help for install-l, --lang string Language the chaincode is written in (default "golang")-n, --name string Name of the chaincode-p, --path string Path to chaincode--peerAddresses stringArray The addresses of the peers to connect to--tlsRootCertFiles stringArray If TLS is enabled, the paths to the TLS root cert files of the peers to connect to. The order and number of certs specified should match the --peerAddresses flag-v, --version string Version of the chaincode specified in install/instantiate/upgrade commandsGlobal Flags:--cafile string Path to file containing PEM-encoded trusted certificate(s) for the ordering endpoint--certfile string Path to file containing PEM-encoded X509 public key to use for mutual TLS communication with the orderer endpoint--clientauth Use mutual TLS when communicating with the orderer endpoint--connTimeout duration Timeout for client to connect (default 3s)--keyfile string Path to file containing PEM-encoded private key to use for mutual TLS communication with the orderer endpoint-o, --orderer string Ordering service endpoint--ordererTLSHostnameOverride string The hostname override to use when validating the TLS connection to the orderer--tls Use TLS when communicating with the orderer endpoint--tlsHandshakeTimeShift duration The amount of time to shift backwards for certificate expiration checks during TLS handshakes with the orderer endpoint--transient string Transient map of arguments in JSON encoding
参数 | 类型 | 含义 |
---|---|---|
-- connectionProfile | string | 网络访问信息文件路径,目前仅支持 peer 连接信息 |
-- peerAddresses | stringArray | 请求所发往的 peer 地址列表 |
--tlsRootCertFiles | stringArray | 所连接的 peer 的信任 TLS 根证书 |
Peer会尝试编译链码,如果编译成功,则将安装包以二进制的形式储存到指定路径的chaincodes子目录下,并利用元数据标签和安装包生成的SHA256值作为文件名。
Peer会尝试编译链码,如果编译成功,则将安装包以二进制的形式储存到指定路径的chaincodes子目录下,并利用元数据标签和安装包生成的SHA256值作为文件名。
注意,安装操作需要是Peer认可的组织管理员身份(证书在Peer的admincerts目录下存在)。
查询和批准链码
通道内组织在部署链码前需要足够多的组织管理员对链码定义进行投票批准。链码定义包括链码名称、版本、序列号、背书和验证参数、是否需要初始化、链码包Id,以及可能带有的私密数据集合配置等。操作涉及queryinstalled、getinstalled-package、approveformyorg、checkcommitrea-diness四个链码生命周期子命令。
queryinstalled子命令可以查询目标Peer上已经安装的链码信息。支持的参数包括:
●--connectionProf ile string,网络访问信息文件路径,目前仅支持Peer连接信息。
●-O,--output string,结果输出的格式,目前支持格式化为json格式。
●--peerAddresses stringArray,请求所发往的Peer地址列表。
●--tlsRootCertFiles stringArray,所连接的Peer的信任的TLS根证书。getinstalledpackage子命令可以获取指定的链码安装包(与发送给Peer的安装包内容相同)。支持参数包括:
●--connectionProf ile string,网络访问信息文件路径,目前仅支持Peer连接信息。
●--output-directory string,将获取到的链码安装包保存到指定路径,默认为当前路径。
●--package-id string,所要获取的链码安装包的ID。
●--peerAddresses stringArray,请求所发往的Peer地址列表。
●--tlsRootCertFiles stringArray,所连接的Peer的信任的TLS根证书。
approveformyorg子命令允许用户将链码的定义发送给Peer进行背书,通过后发给Orderer进行排序和确认。所有需要执行链码的组织都需要完成此步骤。默认情况下,只有通道内大多数组织(通道内的Channel/Application/LifecycleEndorsement策略指定,默认为通道内大多数成员)都批准了链码定义,对应链码才能在通道内部署运行。支持的参数包括:
●--channel-config-policy string,指定链码的背书策略名称,该策略名称需要提前存储在通道策略配置中,默认为Channel/Application/Endorsement策略(默认为通道内大多数成员组织背书)。
●-C,--channelID string,执行命令面向的通道名称。
●--collections-conf ig string,启用私密数据功能时,指定集合文件的路径。
●--connectionProf ile string,网络访问信息文件路径,目前仅支持Peer连接信息。
●-E,--endorsement-plugin string,链码所使用的背书插件的名称。
●--init-required,是否需要调用Init方法对链码进行初始化。
●-n,--name string,链码名称。
●--package-id string,链码安装包的名称。
●--peerAddresses stringArray,所连接的Peer节点列表。
●--sequence int,通道内对链码进行定义的序列号(默认为1),每次更新链码定义则需要递增。
●--signature-policy string,指定链码的(基于签名的)背书策略,默认采用Channel/Application/Endorsement指定的策略(默认为通道内大多数成员组织背书),不能与--channel-conf ig-policy同时使用。
●--tlsRootCertFiles stringArray,连接Peer启用TLS时,所信任的TLS根证书列表(注意与Peer地址顺序匹配)。
●-V,--validation-plugin string,链码所使用的校验系统插件名称。
●--waitForEvent,是否等待事件以确认交易在各个Peer提交(默认开启)。
●--waitForEventTimeout duration,等待事件的时间(默认为30s)。
checkcommitreadiness子命令可以获取指定的链码安装包当前的批准状态,调用_lifecycle链码CheckCommitReadiness方法(位于core/chaincode/lifecycle/scc.go)。支持参数与approveformyorg子命令类似。
提交链码并查询状态
通道内链码得到足够多的组织批准后,将成为可以合法运行的链码。此时,任意通道内组织可以使用commit子命令发起提交操作。链码定义被成功提交到通道后,通道内成员可以使用链码(如进行调用)。支持的参数包括:
●--channel-config-policy string,指定链码的背书策略名称,该策略名称需要提前存储在通道策略配置中,默认为Channel/Application/Endorsement策略(默认为通道内大多数成员组织背书)。
●-C,--channelID string,执行命令面向的通道名称。
●--collections-conf ig string,启用私密数据功能时,指定集合文件的路径。
●--connectionProf ile string,网络访问信息文件路径,目前仅支持Peer连接信息。
●-E,--endorsement-plugin string,链码所使用的背书插件的名称。
●--init-required,是否需要调用Init方法对链码进行初始化。
●-n,--name string,链码名称。
●--package-id string,链码安装包的名称。
●--peerAddresses stringArray,所连接的Peer节点列表。
●--sequence int,通道内对链码进行定义的序列号(默认为1),每次更新链码定义则需要递增。
●--signature-policy string,指定链码的(基于签名的)背书策略,默认采用Channel/Application/Endorsement指定的策略(默认为通道内大多数成员组织背书),不能与--channel-conf ig-policy同时使用。
●--tlsRootCertFiles stringArray,连接Peer启用TLS时,所信任的TLS根证书列表(注意与Peer地址顺序匹配)。
●-V,--validation-plugin string,链码所使用的校验系统插件名称。
●--waitForEvent,是否等待事件以确认交易在各个Peer提交(默认开启)。
●--waitForEventTimeout duration,等待事件的时间(默认为30s)。
●-C,--channelID string,执行命令的通道名称。
●--connectionProf ile string,网络访问信息文件路径,目前仅支持Peer连接信息。
●-n,--name string,链码名称。
●-O,--output string,结果输出的格式,目前支持json格式。
●--peerAddresses stringArray,所连接的Peer地址列表。
●--tlsRootCertFiles stringArray,连接Peer启用TLS时,所信任的TLS根证书列表(注意与Peer地址顺序匹配)。
首先使用commit子命令提交已经得到批准的链码定义,然后使用querycommitted子命令查询提交状态
使用私有数据
在批准和提交链码定义时,可以通过--collections-conf ig collection.json来指定与私密数据相关的集合配置(Fabric v1.1.0开始支持),可以实现在同一通道内私密数据的调用只有部分成员共享。如果不指定该参数则默认不启用该特性,意味着通道内所有成员都可以看到链码调用结果。
collections_config.json
配置文件示例 :
[{"name": "collection1", // 集合名称"policy": "OR('Org1MSP.member')", // 集合成员"requiredPeerCount": 0, // 背书之前至少扩散私有数据到的节点数"maxPeerCount": 3, // 背书之前尝试扩散最多节点个数, 不能小于 requiredPeerCount"blockToLive": 1000000, // 私有数据保存时长 0 意味着永不过期"memberOnlyRead": true, // 是否只允许集合成员来读取私有数据"memberOnlyWrite": true ,// 是否只允许集合成员来发起对私有数据的写交易"endorsementPolicy": "OR('Org1MSP.member')" ,// 指定对私有数据写操作时的背书策略"signaturePolicy": "OR('Org1MSP.member')" // 指定使用签名策略
},{"name": "collection2","policy": "OR('Org2MSP.member')","requiredPeerCount": 0,"maxPeerCount": 3,"blockToLive": 1,"memberOnlyRead": true}
]
其中,collection.json中定义了collection1和collection2两个集合,其成员分别为Org1、Org2两个组织。当在链码逻辑中指定某个键值属于特定集合时,只有集合内成员能看到明文的读写集合,非集合成员即使在同一通道内也无法获取私密数据。对应policy只支持OR语法,指定哪些组织可以看到私密数据集合。
requiredPeerCount和maxPeerCount指定了在执行背书过程中尝试扩散数据到其他合法节点的个数,避免因背书节点的突然故障而导致私密数据丢失。背书阶段未获取私密数据的合法节点,在提交阶段会尝试从其他节点来拉取私密数据。
调用链码
通过 peer chaincode invoke
命令(实现位于internal/peer/chaincode)可以调用运行中链码定义的方法,所指定的函数名和参数会被传到链码的Invoke()方法进行处理。调用链码操作需要同时与Peer和Orderer打交道。
Invoke the specified chaincode. It will try to commit the endorsed transaction to the network.Usage:peer chaincode invoke [flags]Flags:-C, --channelID string The channel on which this command should be executed--connectionProfile string Connection profile that provides the necessary connection information for the network. Note: currently only supported for providing peer connection information-c, --ctor string Constructor message for the chaincode in JSON format (default "{}")-h, --help help for invoke-I, --isInit Is this invocation for init (useful for supporting legacy chaincodes in the new lifecycle)-n, --name string Name of the chaincode--peerAddresses stringArray The addresses of the peers to connect to--tlsRootCertFiles stringArray If TLS is enabled, the paths to the TLS root cert files of the peers to connect to. The order and number of certs specified should match the --peerAddresses flag--waitForEvent Whether to wait for the event from each peer's deliver filtered service signifying that the 'invoke' transaction has been committed successfully--waitForEventTimeout duration Time to wait for the event from each peer's deliver filtered service signifying that the 'invoke' transaction has been committed successfully (default 30s)Global Flags:--cafile string Path to file containing PEM-encoded trusted certificate(s) for the ordering endpoint--certfile string Path to file containing PEM-encoded X509 public key to use for mutual TLS communication with the orderer endpoint--clientauth Use mutual TLS when communicating with the orderer endpoint--connTimeout duration Timeout for client to connect (default 3s)--keyfile string Path to file containing PEM-encoded private key to use for mutual TLS communication with the orderer endpoint-o, --orderer string Ordering service endpoint--ordererTLSHostnameOverride string The hostname override to use when validating the TLS connection to the orderer--tls Use TLS when communicating with the orderer endpoint--tlsHandshakeTimeShift duration The amount of time to shift backwards for certificate expiration checks during TLS handshakes with the orderer endpoint--transient string Transient map of arguments in JSON encoding
注意,invoke是异步操作,invoke成功只能保证交易已经进入Orderer进行排序,但无法保证最终写到账本中(例如交易未通过Committer验证而被拒绝)。需要通过事件监听或主动查询等方式来进行确认交易是否最终写到账本上。
查询链码
查询链码可以通过 peer chaincode query
子命令。
该子命令实际上是invoke操作与Peer打交道的部分,即将签名后的Proposal发给指定的Peer节点的ProcessProposal()gRPC接口。最终将-c指定的命令参数发送给了链码中的Invoke()方法执行。
query操作与invoke操作的区别在于,query操作用来查询Peer上账本状态(需要链码支持查询逻辑),不生成交易,也不需要与Orderer打交道。同时,query命令默认只返回第一个Peer的查询结果。
Get endorsed result of chaincode function call and print it. It won't generate transaction.Usage:peer chaincode query [flags]Flags:-C, --channelID string The channel on which this command should be executed--connectionProfile string Connection profile that provides the necessary connection information for the network. Note: currently only supported for providing peer connection information-c, --ctor string Constructor message for the chaincode in JSON format (default "{}")-h, --help help for query-x, --hex If true, output the query value byte array in hexadecimal. Incompatible with --raw-n, --name string Name of the chaincode--peerAddresses stringArray The addresses of the peers to connect to-r, --raw If true, output the query value as raw bytes, otherwise format as a printable string--tlsRootCertFiles stringArray If TLS is enabled, the paths to the TLS root cert files of the peers to connect to. The order and number of certs specified should match the --peerAddresses flagGlobal Flags:--cafile string Path to file containing PEM-encoded trusted certificate(s) for the ordering endpoint--certfile string Path to file containing PEM-encoded X509 public key to use for mutual TLS communication with the orderer endpoint--clientauth Use mutual TLS when communicating with the orderer endpoint--connTimeout duration Timeout for client to connect (default 3s)--keyfile string Path to file containing PEM-encoded private key to use for mutual TLS communication with the orderer endpoint-o, --orderer string Ordering service endpoint--ordererTLSHostnameOverride string The hostname override to use when validating the TLS connection to the orderer--tls Use TLS when communicating with the orderer endpoint--tlsHandshakeTimeShift duration The amount of time to shift backwards for certificate expiration checks during TLS handshakes with the orderer endpoint--transient string Transient map of arguments in JSON encoding
升级链码
链码升级过程需要重复peer lifecycle chaincode相关命令,来执行完整的生命周期,具体步骤如下:
1)更新旧版本链码的源代码,并重新打包链码包。
2)将新的链码包再次安装到Peer,获取新的包Id。注意,相对旧版本要递增版本号。
3)按照策略,通道内足够多组织都要重新对新版本的链码定义进行批准。注意,序列号要递增。
4)通道内足够多组织批准定义后,可以提交新版本链码定义到通道。
5)再次调用链码,确保链码已经自动更新为新的版本。
Hyperledger Fabric 管理链码 peer lifecycle chaincode 指令使用相关推荐
- [求助]hyperledger fabric在创建peer通道时出现this policy requires 1 of the 'Writers' sub-policies to be……
毕业设计打算做区块链有关的内容,目前买了本机械工业出版社出版的<区块链开发实战 hyperledger Fabric关键技术与案例分析>这本书来学习,可能由于版本问题,在使用书上的配置文件 ...
- 3.Hyperledger Fabric v2.0 CA组件
Hyperledger Fabric v2.0 CA组件 目的: 通过CA服务生成msp证书和tls证书,并启动fabric网络 由于使用CA生成证书时,需要注册为各个组织生成证书,为了便于理解,所以 ...
- Hyperledger Fabric的test-network启动过程Bash源码详解
前言 在基于Debian搭建Hyperledger Fabric 2.4开发环境及运行简单案例中,我们已经完成了Fabric 2.4的环境搭建及fabric-samples/test-network官 ...
- Hyperledger Fabric 2.x 单机部署多节点网络
本博客主要记录搭建一个3个排序节点.4个组织的每个组织各2个节点的fabric区块链网络 单机部署多节点网络 1.相关环境的安装与配置 2.生成相关的证书文件 3.生成相关的通道配置文件 4.生成do ...
- Hyperledger Fabric学习笔记(四)- fabric单机部署 solo 版
一.前言: 1.底下的配置文件很重要,一配置错了就有问题了,下面附出这篇文章所需要的配置文件,下载链接:https://download.csdn.net/download/u012561176/15 ...
- Hyperledger Fabric 2.2实战记录(二)
四.使用Fabric-SDK-Go调用链码 在Org1的peer上使用SDK 1.安装Fabric-SDK-GO go get github.com/hyperledger/fabric-sdk-go ...
- Hyperledger Fabric 2.0 chaincode lifecycle
Chaincode Lifecycle 环境准备参见 Fabric 2.0 debug 环境准备 脚本部分 2.0 新增 _lifecycle 系统 chaincode 管理 Chaincode 生命 ...
- Hyperledger Fabric 2.0 官方文档中文版 第6章 教程(上)
Hyperledger Fabric 2.0 官方文档中文版第6章 教程上 总目录 6.教程(上) 将智能合约部署到通道 启动网络 Logspout设置 打包智能合约 安装链码包 批准链码定义 将链码 ...
- 基于Debian搭建Hyperledger Fabric 2.4开发环境及运行简单案例
前言 在基于truffle框架实现以太坊公开拍卖智能合约中我们已经实现了以太坊智能合约的编写及部署,但其工作方式注定其只能应用于有限的业务场景中.相比之下,基于超级账本的Fabric具有高可扩展性和高 ...
- Hyperledger Fabric无系统通道启动及通道的创建和删除
前言 在Hyperledger Fabric组织的动态添加和删除中,我们已经完成了在运行着的网络中动态添加和删除组织,但目前为止,我们启动 orderer 节点的方式都是通过系统通道的方式,这样自带系 ...
最新文章
- 【青少年编程】【四级】绘图程序优化
- 检查用户是否正在使用IE
- 中国量化投资将呈现三大发展趋势
- matlab球面波衍射,单色点源矩孔菲涅耳衍射光场的计算与模拟
- SQL建表公共字段脚本
- Docker 环境下如何 安装 Zookeeper
- php文件管理 打包,Thinkphp6如何利用ZipArchive打包下载文件
- 对发表论文的深层次思考
- HTTP对外接口,如何增加签名机制
- php遍历数组对象数组长度,PHP循环遍历对象数组会产生意外结果
- 25 岁的 JavaScript 都经历了什么?
- linux 生成rsa密钥,linux下生成rsa密钥的方法
- 信息学奥赛一本通知识集锦+往年真题
- cao方法matlab程序,偏最小二乘法 matlab程序 [转]
- element组件官网
- 阿里王坚:用“机器智能”取代“人工智能”概念
- QA - 有两种药片A和B,外观一样功效不同,每次需要吃一个A+B;拿出来2A+B,问该怎么吃?
- GetLocalTime 和 GetSystemTime 的区别
- 【案例】郑州商品交易所:搭建AI预测模型,提升智能决策水平
- 强势来袭!取代传统PC开辟新增长极,这款“云电脑”凭啥?
热门文章
- Xcode 8 过滤系统输出
- 基于树莓派的语音对话助手 百度机器人 适合入门
- 写给0-3岁产品经理的第2封信:《产品经理的基本功——产品设计能力》
- php集成c sdk,GitHub - cuncle/spider-php-sdk
- 《TCP/IP详解 卷1:协议》学习笔记(未完待续)
- 未转变者服务器保存红字警告,未转变者3.0怎么设置自己开的服
- 千兆宽带网接入电脑电脑却只有百兆
- 十分钟带你认识Node.js
- EXCEL批量修改文件名
- IIS6/IIS7以上、Nginx、Apache拦截屏蔽垃圾蜘蛛UA爬行降低负载方法IIS7.5如何限制某UserAgent 禁止访问