千家信息网

以太坊智能合约部署与交互的方法是什么

发表于:2025-01-28 作者:千家信息网编辑
千家信息网最后更新 2025年01月28日,这篇文章主要介绍"以太坊智能合约部署与交互的方法是什么",在日常操作中,相信很多人在以太坊智能合约部署与交互的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"以
千家信息网最后更新 2025年01月28日以太坊智能合约部署与交互的方法是什么

这篇文章主要介绍"以太坊智能合约部署与交互的方法是什么",在日常操作中,相信很多人在以太坊智能合约部署与交互的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"以太坊智能合约部署与交互的方法是什么"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

启动容器来执行geth命令

root@ubu-blockchain2:~# docker run -i blockchain101/ethereum-geth:1.6.5 geth attach http://45.32.252.88:8201Welcome to the Geth JavaScript console!instance: Geth/01/v1.6.5-stable/linux-amd64/go1.8coinbase: 0x4c57e7e9c2f728046ddc6e96052056a241bdbd0aat block: 6064 (Wed, 02 Aug 2017 01:13:50 UTC) datadir: /ethcluster/779977/data/01 modules: admin:1.0 eth:1.0 net:1.0 rpc:1.0 web3:1.0

查看我们的账户和余额

eth.getBalance(eth.accounts[0])11000000000000000000eth.getBalance(eth.accounts[1])0eth.accounts[0]"0x4c57e7e9c2f728046ddc6e96052056a241bdbd0a"> eth.accounts[1]"0xe82e2f0a5abd8774767b9751659976f9c4f59181"

发起一笔交易

eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:web3.toWei(3,'ether')})"0x0075da712d26aea17d6647035107f509e13eaf3d113c1577db14d4cc4216caec"

查看交易细节

>  eth.getTransaction("0x0075da712d26aea17d6647035107f509e13eaf3d113c1577db14d4cc4216caec"){  blockHash: "0x3115703894dc6015c96ef4de3e5615f416498ca1f985902b38cd70e27dab8871", blockNumber: 1250, from: "0x4c57e7e9c2f728046ddc6e96052056a241bdbd0a", gas: 90000, gasPrice: 18000000000, hash: "0x0075da712d26aea17d6647035107f509e13eaf3d113c1577db14d4cc4216caec", input: "0x", nonce: 0, r: "0x2aef2c1fa03a0fa4172d21e3383d8c0431d45ec855b9d16efdd5eb2de90c414c", s: "0xc4d530fb7902bf509fe56bfbea4861bf6cc16791afc9c9103c1a18f77407d1f", to: "0xe82e2f0a5abd8774767b9751659976f9c4f59181", transactionIndex: 0, v: "0x17cdb6", value: 3000000000000000000 }> eth.getBalance(eth.accounts[1])3000000000000000000

验证用户0的余额

> eth.getBalance(eth.accounts[0])7999622000000000000

编写一个简单的合约

contract Sample {uint public value;          function Sample(uint v){value=v;          }          function set(uint v){value=v;          }          function get() constant returns (uint){return value;          }}

在remix网页编译得到ABI接口和合约的二进制代码、

 abi=[{"constant":true,"inputs":[],"name":"value","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"v","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"v","type":"uint256"}],"payable":false,"type":"constructor"}][{    constant: true,    inputs: [],    name: "value",    outputs: [{        name: "",        type: "uint256"}],    payable: false,    type: "function"}, {    constant: false,    inputs: [{        name: "v",        type: "uint256"}],    name: "set",    outputs: [],    payable: false,    type: "function"}, {    constant: true,    inputs: [],    name: "get",    outputs: [{        name: "",        type: "uint256"}],    payable: false,    type: "function"}, {    inputs: [{        name: "v",        type: "uint256"}],    payable: false,    type: "constructor"}]

需要使用eth.contract来定义一个合约类

> sample=eth.contract(abi){  abi: [{      constant: true,      inputs: [],      name: "value",      outputs: [{...}],      payable: false,      type: "function"  }, {      constant: false,      inputs: [{...}],      name: "set",      outputs: [],      payable: false,      type: "function"  }, {      constant: true,      inputs: [],      name: "get",      outputs: [{...}],      payable: false,      type: "function"  }, {      inputs: [{...}],      payable: false,      type: "constructor"  }],  eth: {    accounts: ["0x4c57e7e9c2f728046ddc6e96052056a241bdbd0a", "0xe82e2f0a5abd8774767b9751659976f9c4f59181"],    blockNumber: 6225,    coinbase: "0x4c57e7e9c2f728046ddc6e96052056a241bdbd0a",    compile: {      lll: function(),      serpent: function(),      solidity: function()},    defaultAccount: undefined,    defaultBlock: "latest",    gasPrice: 18000000000,    hashrate: 0,    mining: false,    pendingTransactions: [],    protocolVersion: "0x3f",    syncing: false,    call: function(),    contract: function(abi),    estimateGas: function(),    filter: function(fil, callback),    getAccounts: function(callback),    getBalance: function(),    getBlock: function(),    getBlockNumber: function(callback),    getBlockTransactionCount: function(),    getBlockUncleCount: function(),    getCode: function(),    getCoinbase: function(callback),    getCompilers: function(),    getGasPrice: function(callback),    getHashrate: function(callback),    getMining: function(callback),    getPendingTransactions: function(callback),    getProtocolVersion: function(callback),    getRawTransaction: function(),    getRawTransactionFromBlock: function(),    getStorageAt: function(),    getSyncing: function(callback),    getTransaction: function(),    getTransactionCount: function(),    getTransactionFromBlock: function(),    getTransactionReceipt: function(),    getUncle: function(),    getWork: function(),    iban: function(iban),    icapNamereg: function(),    isSyncing: function(callback),    namereg: function(),    resend: function(),    sendIBANTransaction: function(),    sendRawTransaction: function(),    sendTransaction: function(),    sign: function(),    signTransaction: function(),    submitTransaction: function(),    submitWork: function()  },  at: function(address, callback),  getData: function(),  new: function()}

合约的二进制代码赋值给SampleHEX方便使用

SampleHEX="0x6060604052341561000c57fe5b60405160208061013a833981016040528080519060200190919050505b806000819055505b505b60f9806100416000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633fa4f24514604e57806360fe47b11460715780636d4ce63c14608e575bfe5b3415605557fe5b605b60b1565b6040518082815260200191505060405180910390f35b3415607857fe5b608c600480803590602001909190505060b7565b005b3415609557fe5b609b60c2565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b600060005490505b905600a165627a7a72305820208c8101070c8ba5a9b32db2bf4b8062a9ba50bc2869c39ac2297938756540e80029"

把合约代码部署上链

> thesample=sample.new(1,{from:eth.accounts[0],data:SampleHEX,gas:3000000}){  abi: [{      constant: true,      inputs: [],      name: "value",      outputs: [{...}],      payable: false,      type: "function"  }, {      constant: false,      inputs: [{...}],      name: "set",      outputs: [],      payable: false,      type: "function"  }, {      constant: true,      inputs: [],      name: "get",      outputs: [{...}],      payable: false,      type: "function"  }, {      inputs: [{...}],      payable: false,      type: "constructor"  }],  address: undefined,  transactionHash: "0xee74bcb4461c9712ec9aca96a5a3a4c3c64be1213854d519fc8e5432b554f7a1"}

查看交易细节

> samplerecpt=eth.getTransactionReceipt("0xee74bcb4461c9712ec9aca96a5a3a4c3c64be1213854d519fc8e5432b554f7a1"){  blockHash: "0xddba16545af882835fb9a69a0e5f3b9287c61664837d5ea0068b38575cb665c5",  blockNumber: 6246,  contractAddress: "0x7504fa9d64ab290844b82660d43b310f8fba0276",  cumulativeGasUsed: 141836,  from: "0x4c57e7e9c2f728046ddc6e96052056a241bdbd0a",  gasUsed: 141836,  logs: [],  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",  root: "0xd1093ecaca9cc0d10e82a533a15feccedf7ff5c79fb3ebd9366ec0b35dbef478",  to: null,  transactionHash: "0xee74bcb4461c9712ec9aca96a5a3a4c3c64be1213854d519fc8e5432b554f7a1",  transactionIndex: 0}

合约命名

> samplecontract=sample.at("0x7504fa9d64ab290844b82660d43b310f8fba0276"){  abi: [{      constant: true,      inputs: [],      name: "value",      outputs: [{...}],      payable: false,      type: "function"  }, {      constant: false,      inputs: [{...}],      name: "set",      outputs: [],      payable: false,      type: "function"  }, {      constant: true,      inputs: [],      name: "get",      outputs: [{...}],      payable: false,      type: "function"  }, {      inputs: [{...}],      payable: false,      type: "constructor"  }],  address: "0x7504fa9d64ab290844b82660d43b310f8fba0276",  transactionHash: null,  allEvents: function(),  get: function(),  set: function(),  value: function()}

合约查看功能函数get(),然后调用set()函数,再get()查看时已经改变了

samplecontract.get.call()1> samplecontract.set.sendTransaction(9, {from:eth.accounts[0], gas:3000000})"0x822ee6fb4caceb7e844c533f7f3bc57806f7cb3676fb3066eb848cca46b2f38a"> samplecontract.get.call()9

我们再打开一个终端,打开cluster1的peer02的控制台,直接at到上一个终端部署的智能合约地址并进行set操作

root@ubu-blockchain2:~/ethereum-docker/ethereum-docker/ethereum-testnet-docker/dockercomposefiles# docker run -i blockchain101/ethereum-geth:1.6.5 geth attach http://45.32.252.88:9201Welcome to the Geth JavaScript console!>  abi=[{"constant":true,"inputs":[],"name":"value","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"v","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"v","type":"uint256"}],"payable":false,"type":"constructor"}]> sample=eth.contract(abi)SampleHEX="0x6060604052341561000c57fe5b60405160208061013a833981016040528080519060200190919050505b806000819055505b505b60f9806100416000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633fa4f24514604e57806360fe47b11460715780636d4ce63c14608e575bfe5b3415605557fe5b605b60b1565b6040518082815260200191505060405180910390f35b3415607857fe5b608c600480803590602001909190505060b7565b005b3415609557fe5b609b60c2565b6040518082815260200191505060405180910390f35b60005481565b806000819055505b50565b600060005490505b905600a165627a7a72305820208c8101070c8ba5a9b32db2bf4b8062a9ba50bc2869c39ac2297938756540e80029"

直接把合约地址赋值并进行set操作

samplecontract=sample.at("0x7504fa9d64ab290844b82660d43b310f8fba0276")> samplecontract.get.call()9

简单的方法来了。智能合约的部署需要编译,这里用在线编译:
https://ethereum.github.io/browser-solidity/#version=soljson-v0.4.14+commit.c2215d46.js
修改编译好的abi和对象名称:

这里在网上找了个代币的只能合约,可以进行充值、转账和查询,issue 函数可以向充值以太到合约账户,transfer 函数可以向其他账号发送token,getBalance 函数可以获取某个账号的token余额,代码如下:pragma solidity ^0.4.2;contract Token {             address issuer;             mapping (address => uint) balances;             event Issue(address account, uint amount);             event Transfer(address from, address to,uint amount);             function Token() {                 issuer = msg.sender;             }             function issue(address account, uintamount) {                 if (msg.sender != issuer) throw;                 balances[account] += amount;             }             function transfer(address to, uint amount){                 if (balances[msg.sender] < amount)throw;                 balances[msg.sender] -= amount;                 balances[to] += amount;                 Transfer(msg.sender, to, amount);             }             function getBalance(address account)constant returns (uint) {                 return balances[account];             }         }
修改编译好的gas和对象名称:varbrowser_untitled_sol_tokenContract =web3.eth.contract([{"constant":false,"inputs":[{"name":"account","type":"address"},{"name":"amount","type":"uint256"}],"name":"issue","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"amount","type":"uint256"}],"name":"transfer","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"getBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"account","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Issue","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"from","type":"address"},{"indexed":false,"name":"to","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Transfer","type":"event"}]);var token =browser_untitled_sol_tokenContract.new(   {     from: web3.eth.accounts[0],     data:'0x6060604052341561000f57600080fd5b5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b5b6103d2806100616000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063867904b414610054578063a9059cbb14610096578063f8b2cb4f146100d8575b600080fd5b341561005f57600080fd5b610094600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091908035906020019091905050610125565b005b34156100a157600080fd5b6100d6600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101d2565b005b34156100e357600080fd5b61010f600480803573ffffffffffffffffffffffffffffffffffffffff1690602001909190505061035c565b6040518082815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561018057600080fd5b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505b5050565b80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054101561021e57600080fd5b80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555080600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055507fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef338383604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a15b5050565b6000600160008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490505b9190505600a165627a7a723058204afe007a03446d43d13ac892e6dba9d032f540a11ff427d26c22560727cbea2f0029',     gas: '4300000'   }, function (e, contract){    console.log(e, contract);if (typeof contract.address !=='undefined') {         console.log('Contract mined! address:' + contract.address + ' transactionHash: ' + contract.transactionHash);    } })

此时输入合约部署的实例a_demotypes, 可以看到a_demotypes的详情。

控制台调用

> a_demotypes{  abi: [{      constant: false,      inputs: [{...}],      name: "f",      outputs: [{...}],      payable: false,      type: "function"  }],  address: "0x54ed7a5f5a63ddada3bfe83b3e632adabaa5fc2f",  transactionHash: "0x69cde62bcd6458e14f40497f4840f422911d63f5dea2b3a9833e6810db64a1c9",  allEvents: function(),  f: function()}

这里重点就是address表示的是合约的地址,你会发现这个和账号的信息结果一样,其实你也可以把这个合约地址看做是一个账号地址,后面我们外部调用到的就是这个合约地址。

充值token.issue.sendTransaction(eth.accounts[0],100, {from: eth.accounts[0]});发送 tokentoken.transfer(eth.accounts[1], 30, {from:eth.accounts[0]})查看余额token.getBalance()控制台调用就不多说,和Java对象调用一样,直接调用即可

外部接口与智能合约交互
以太坊对外提供的有很多接口JSON RPC接口,web3接口,这里我们用JSON RPC接口。

合约交互的原理
合约的交互都是一次交易,而我们要做的就是把要调用的方法和参数按照api规定的以参数的形式向区块请求一次交易,ethereum接收到我们的请求后通过解析传递的参数来执行相关的合约代码。
RPC接口给我们提供了俩个方法:eth_sendTransaction和eth_call。

eth_sendTransactionCreatesnew message call transaction or a contract creation, if the data field containscode.ParametersObject - The transaction objectfrom: DATA, 20 Bytes - The address the transaction is send from.to: DATA, 20 Bytes - (optional when creating new contract) The address the transaction is directed to.gas: QUANTITY - (optional, default: 90000) Integer of the gas provided for the transaction execution. It will return unused gas.gasPrice: QUANTITY - (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gasvalue: QUANTITY - (optional) Integer of the value send with this transactiondata: DATA - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see Ethereum Contract ABInonce: QUANTITY - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.

可以看到,如果我们创建的为合约时,我们只需要from,to(文档上写的是可选的,但是实际操作中没有to为null的话合约不能正常执行,建议还是加上,这个值就是前面我们部署合约后生成的合约address),data。Data的属性的值具体可以看Contract ABI。这里大概说下:
Data的值相对来说不是固定的,具体怎么生成与合约的参数类型,参数数量都有关联。这里我们以部署的token合约的三个方法为例:

充值issue (address account, uint amount)
这个方法有俩个参数,address充值账号,uint充值数量。
根据Contract ABI,data值应该为方法名的sha3的前8个字节+参数的64字节,不够前面补充为0。
这里方法名并不是issue (address account, uint amount)而是issue(address,uint256)的sha3值。

web3.sha3("issue(address,uint256)")"0x867904b44b606800f6f10498e11292d04ea19bfc7fe4bc0f1695aa516381f73d"

我们往第一个账号充值10,这里的数据不是以太币,而是我们自己创建的代币。

 eth.accounts[0]"0x0cc9684af605bae10de801218321c1336bb62946"

将10转换为16进制为

000000000000000000000000000000000000000000000000000000000000000a

那么data的数据为:

0x867904b4000000000000000000000000fdf57e81872562a6112656f961944ce821fdf7eb000000000000000000000000000000000000000000000000000000000000000a

那么最后我们调用eth_sendTransaction方法传递参数JSON对象为:

{    from:0xfdf57e81872562a6112656f961944ce821fdf7eb, to:0x7fe133950fc010ce41322d88f64f1918b9abb3a3, data: 0x867904b4000000000000000000000000fdf57e81872562a6112656f961944ce821fdf7eb000000000000000000000000000000000000000000000000000000000000000a }

返回:此交易的hash值,此时该交易还没有执行,只是创建,还需要矿工通过挖矿才能完成。
调用接口方法:

JsonRpcHttpClient client = newJsonRpcHttpClient(new URL("http://127.0.0.1:8545"));Object result = client.invoke(methodName,params, Object.class);

通过控制台查看第一个账号已有代币:

token.getbalance(eth.accounts[0])

执行调用接口代码。返回交易hash值:

0x2013764d1c3fea680f9015353497aa5f9f8d61580a3bd0524b3613b34329c095

此时控制台输入:

交易和充值一样,需要注意的是代币转出账号为from属性的值,代币转入账号为data属性里的值,to对应的是合约地址。
eth_call

Executes anew message call immediately without creating a transaction on the block chain.ParametersObject - The transaction call objectfrom: DATA, 20 Bytes - (optional) The address the transaction is sent from.to: DATA, 20 Bytes - The address the transaction is directed to.gas: QUANTITY - (optional) Integer of the gas provided for the transaction execution. eth_call consumes zero gas, but this parameter may be needed by some executions.gasPrice: QUANTITY - (optional) Integer of the gasPrice used for each paid gasvalue: QUANTITY - (optional) Integer of the value send with this transactiondata: DATA - (optional) Hash of the method signature and encoded parameters. For details seeEthereum Contract ABIQUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending", see the default block parameter

这个方法返回一条信息给我们,相当于数据库的查询功能,参数也是三个,from,to,data,数据格式都是一样的。
查询getBalance(address account)
查询方法hash码:

 web3.sha3("getBalance(address)")"0xf8b2cb4f3943230388faeee074f1503714bff212640051caba01411868d14ae3"

查询我们上一步充值的账号,那么传递的参数data为:

0xf8b2cb4f000000000000000000000000fdf57e81872562a6112656f961944ce821fdf7eb

eth_call方法最后参数为:

{       from: 0xfdf57e81872562a6112656f961944ce821fdf7eb, to:0x7fe133950fc010ce41322d88f64f1918b9abb3a3, data:0xf8b2cb4f000000000000000000000000fdf57e81872562a6112656f961944ce821fdf7eb }

注意,这个方法需要俩参数,处理一个JSONobject外,还有一个字符串参数,这俩可以为""或者"latest", "earliest" or "pending"
调用接口返回一个16进制字符串:
0x0000000000000000000000000000000000000000000000000000000000000071就是该账号的代币数量,转换为十进制为:113,与控制查询一致。

这就是一个智能合约的交互过程。是不是很简单啊。

到此,关于"以太坊智能合约部署与交互的方法是什么"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

合约 方法 参数 账号 接口 交易 智能 以太 地址 代码 就是 代币 控制 查询 函数 控制台 编译 余额 对象 数据 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 软件开发员工管理 护苗...网络安全课 广东安卓软件开发需要多少钱 如何看待违反网络安全法 什么是网络音乐服务器 灵魂潮汐不同服务器可以一起玩吗 阿里云服务器开放安全组 软件开发者是否构成侵犯著作权 南邮网络技术与应用大纲解答 文件服务器共享文件管理规定 秦皇岛 软件开发 NST网络安全 2007年梦幻西游服务器 数据库面试优缺点 软件开发很费键盘吗 多台服务器管理 高中学历学软件开发好就业吗 监狱网络安全机制建设研究 我国网络安全法颁布的时间 网络安全与信息应急演练 梅州软件开发公司有哪些 笔记本电脑怎样设置网络安全流程 宝鸡网络技术调试 堡垒机监控 服务器操作 cog网络安全峰会 医院信息网络安全管理办法 计算机网络技术基础第二版网课 特朗普关于网络安全的十大雷语 互联网金融科技通知 国地税网络安全合作制度
0