|
|
|
|
移动端

金冠网上投注最高占成:从0到1 手把手教你建一个区块链

本文来源:http://www.2233122.com/www_2k2k_cc/

太阳城娱乐网最快登入,其他国家的手机号都是几位  日本和我国一样也是11位的,080、090开头他们怎么用得了那么多号呢  10位的有我国台湾、美国、德国、印度、瑞士、荷兰、比例是、法国、菲律宾、澳大利亚等。  本届大赛以“拥抱‘互联网+’时代共筑创新创业梦想”为主题,于今年4月份开始报名,全省共有59所高校的6845个团队完成网上注册,2572个团队通过审核。  “通过太阳能板,将太阳能转化为电能,驱动电机使得营养液循环,可以让植物达到理想的生长状态。大家知道AR和VR区别都很清楚,但是AR和MR混合现实区别在哪里呢?混合显示就是戴上一个眼镜,眼镜里头给你一些信息,而MR是对三维空间有很好的传输,实际是把三维物体放在里头,你围绕着它转看到信息是不一样的。

》却将儿子暴揍了一顿,还在家长群里呼吁抵制日本文化。”也有受访者表示:“‘1元买宝马’、‘下载APP,商品1折拿回家’固然没有多少人会相信,但是,很多人习惯思维,认为虽然没有那么优惠,但折扣多少总会有的,哪想到根本不是那么一回事。家庭医生一直是政策扶持的重点,但在推广上也然也面临着多重困难。首先他们的数据是非常多的,结构性,非结构性,流失的,通过数据平台可以得到最有效的支持。

此外,还有用户发现TimeMachine在后台备份至移动硬盘时,也会出现意外关机的现象。比去年同期提升13.1个百分点。此后,双方成立中俄高铁合作企业工作组,推动合作进展。KeyshareGLINT2在之前的基础上进行了升级,一键操作:一键起飞、一键降落、一键返航、一键跟随;双模定位:内置GPS/GLONASS双模定位系统,继承了一贯优异的飞行稳定性;三轴云台:配置高性能三轴增稳云台;4K相机:超清晰16M/4K拍照录像运动相机,带您用全新的视角去发现世界之美。

近期的区块链重回热点,如果你想深入了解区块链,那就来看一下本文,手把手教你构建一个自己的区块链。

作者:Captain编译来源:51CTO|2019-10-29 15:46

【太阳城娱乐网最快登入 www.2233122.com快译】近期的区块链重回热点,如果你想深入了解区块链,那就来看一下本文,手把手教你构建一个自己的区块链。

弄懂区块链的最快方法-亲自构建一个

看到这篇文章,说明您也是对加密货币的兴起感兴趣,想知道区块链是如何工作的和其背后运行的技术原理。

但是想要搞懂区块链并不容易。我在众多的视频中苦苦钻研,跟随着漏洞百出的教程,经历着因区块链相关案例太少而产生的挫败感。

我喜欢从行动中学习。它迫使我从代码层面处理问题,从而解决问题。如果您和我一样做,那么在本指南的最后,您将拥有一个运行正常的区块链,并对它们的工作原理有深入的了解。

上手准备

请记住,区块链是一个不可变的、连续的记录链,称为块。它们可以包含事务、文件或您喜欢的任何数据。但是重要的是,它们通过使用哈希而被链接在一起。

如果您不确定什么是哈希值,请参考这里。

教程面向的人群?

可以轻松地阅读和编写一些基本的Python,并且对HTTP请求的工作方式有所了解,因为本文将通过HTTP与区块链进行交流。

需要准备什么?

确保已安装 Python 3.6 +(以及pip)。您还需要安装Flask和很棒的Requests库:

  1. pip install Flask==0.12.2 requests==2.18.4 

您还需要HTTP客户端,例如Postman或cURL。

源代码可在此处获得。

步骤1:构建一个区块链

打开你最喜欢的文本编辑器或IDE,我个人喜欢 PyCharm。创建一个名为blockchain.py的新文件。我们将只使用一个文件,但是如果您有困惑了,可以随时参考源代码。

展示区块链

我们将创建一个Blockchain class,它的构造函数会创建一个初始的空列表(用于存储我们的区块链),另一个用于存储事务。这是脚本:

  1. class Blockchain(object):  
  2. def __init__(self):  
  3. self.chain = []  
  4. self.current_transactions = []  
  5. def new_block(self):  
  6. # Creates a new Block and adds it to the chain  
  7. pass  
  8. def new_transaction(self):  
  9. # Adds a new transaction to the list of transactions  
  10. pass  
  11. @staticmethod  
  12. def hash(block):  
  13. # Hashes a Block  
  14. pass  
  15. @property  
  16. def last_block(self):  
  17. Returns the last Block in the chain  
  18. pass  

Blockchain class 的demo

我们的Blockchain class负责管理链。它将存储事物,并具有一些将新块添加到链中的辅助方法。让我们来尝试一些新的方法吧。

Block像什么?

每个Block都有以下的内容:

  • 一个索引,
  • 一个时间戳(Unix时间),
  • 一个交易列表,
  • 一个证明(稍后会有更多说明)
  • 前一个区块的哈希值。

单个区块示例:

  1. block = {  
  2. 'index': 1,  
  3. 'timestamp': 1506057125.900785,  
  4. 'transactions': [  
  5.  
  6. 'sender'"8527147fe1f5426f9dd545de4b27ee00" 
  7. 'recipient'"a77f5cdfa2934df3954a5c7c7da5df1f" 
  8. 'amount': 5,  
  9.  
  10. ],  
  11. 'proof': 324984774000,  
  12. 'previous_hash'"2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"  
  13.  

在这一点上,链的概念应该很明显--每个新区块本身都包含前一个区块的哈希值。这是至关重要的,因为这给予了区块链的不可篡改性:如果攻击者破坏了链中较早的区块,则后续所有的区块都将包含不正确的哈希值。

不知道你能理解嘛,请多花些时间去理解它—这是区块链的核心思想。

添加事物到区块中

我们需要一种将事物添加到区块的方法。我们的new_transaction()方法有效,而且很简单:

  1. class Blockchain(object):  
  2. ...  
  3. def new_transaction(self, sender, recipient, amount):  
  4. "" 
  5. Creates a new transaction to go into the next mined Block  
  6. :param sender: Address of the Sender  
  7. :param recipient: Address of the Recipient  
  8. :param amount: Amount  
  9. :return: The index of the Block that will hold this transaction  
  10. "" 
  11. self.current_transactions.append({  
  12. 'sender': sender,  
  13. 'recipient': recipient,  
  14. 'amount': amount,  
  15. }) 
  16.  
  17. return self.last_block['index'] + 1  

在new_transaction()添加一个新的交易到列表中,它将返回到交易将被添加进去、即将被开采的区块的索引。这对之后提交交易的用户是很有用处的。

创建新区块

当我们Blockchain被实例化,我们需要用一个genesis块来播种它——一个没有前处理的块。还需要向我们的创世区块添加一个“证明”,这是挖掘(或工作证明)的结果。稍后我们将详细讨论挖矿。

除了在构造函数中创建genesis块,我们还将充实new_block()、new_transaction()和hash()的方法:

  1. import hashlib  
  2. import json  
  3. from time import time  
  4. class Blockchain(object):  
  5. def __init__(self):  
  6. self.current_transactions = []  
  7. self.chain = []  
  8. Create the genesis block  
  9. self.new_block(previous_hash=1, proof=100)  
  10. def new_block(self, proof, previous_hash=None):  
  11. "" 
  12. Create a new Block in the Blockchain  
  13. :param proof: The proof given by the Proof of Work algorithm  
  14. :param previous_hash: (Optional) Hash of previous Block  
  15. :return: New Block  
  16. "" 
  17. block = {  
  18. 'index': len(self.chain) + 1,  
  19. 'timestamp'time(),  
  20. 'transactions': self.current_transactions,  
  21. 'proof': proof,  
  22. 'previous_hash': previous_hash or self.hash(self.chain[-1]),  
  23.  
  24. # Reset the current list of transactions  
  25. self.current_transactions = []  
  26. self.chain.append(block)  
  27. return block  
  28. def new_transaction(self, sender, recipient, amount): 
  29. "" 
  30. Creates a new transaction to go into the next mined Block  
  31. :param sender: Address of the Sender  
  32. :param recipient: Address of the Recipient  
  33. :param amount: Amount  
  34. :return: The index of the Block that will hold this transaction  
  35. "" 
  36. self.current_transactions.append({  
  37. 'sender': sender,  
  38. 'recipient': recipient,  
  39. 'amount': amount,  
  40. })  
  41. return self.last_block['index'] + 1  
  42. @property  
  43. def last_block(self):  
  44. return self.chain[-1]  
  45. @staticmethod  
  46. def hash(block):  
  47. "" 
  48. Creates a SHA-256 hash of a Block  
  49. :param block: Block  
  50. :return 
  51. "" 
  52. # We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes  
  53. block_string = json.dumps(block, sort_keys=True).encode()  
  54. return hashlib.sha256(block_string).hexdigest()  

上面的内容应该很简单—我添加了一些注释和文档字符串来帮助保持清楚明了。对区块链的表示几乎完成了。但此时,您一定想知道如何创建、锻造或挖掘新的区块。

了解工作量证明

工作算法(PoW)是在区块链上创建或挖掘新区块的方式。PoW的目标是发现可以解决问题的数字。从数字上来说,很难找到该数字,但是很容易被网络上的任何人进行验证。这是工作证明的核心思想。

我们将看一个非常简单的示例来帮助理解。

让我们决定某个整数X乘以另一个Y的哈希必须以0结尾。因此,对于这个简化的示例,让我们修复。在Python中实现:xy0hash(x * y) = ac23dc...0x = 5

  1. from hashlib import sha256  
  2. x = 5  
  3. y = 0 # We don't know what y should be yet...  
  4. while sha256(f'{x*y}'.encode()).hexdigest()[-1] != "0" 
  5. y += 1  
  6. print(f'The solution is y = {y}' 

解是y = 21。因为,产生的哈希值以0结尾:

  1. hash(5 * 21)= 1253e9373e ... 5e3600155e860 

在比特币中,工作证明算法称为Hashcash。而且与我们上面的示例并没有太大不同。这是矿工为了创建一个新的块而竞相求解的算法。通常,难度由字符串中搜索的字符数决定。然后,通过在交易中获得硬币,矿工将借此获得奖励。

网络能够轻松验证他们的解决方案。

实施基本的工作证明

让我们为区块链实现类似的算法。我们的规则将类似于上面的示例:

找出一个数字 p ,当该数字与上一个块的解决方案进行哈希运算时,将产生一个带有4个前导4个0的哈希。

  1. import hashlib  
  2. import json  
  3. from time import time  
  4. from uuid import uuid4  
  5. class Blockchain(object):  
  6. ...  
  7. def proof_of_work(self, last_proof):  
  8. "" 
  9. Simple Proof of Work Algorithm:  
  10. - Find a number p' such that hash(pp'contains leading 4 zeroes, where p is the previous p'  
  11. - p is the previous proof, and p' is the new proof  
  12. :param last_proof:  
  13. :return 
  14. "" 
  15. proof = 0  
  16. while self.valid_proof(last_proof, proof) is False 
  17. proof += 1  
  18. return proof  
  19. @staticmethod  
  20. def valid_proof(last_proof, proof):  
  21. "" 
  22. Validates the Proof: Does hash(last_proof, proof) contain 4 leading zeroes?  
  23. :param last_proof: Previous Proof  
  24. :param proof: Current Proof  
  25. :returnTrue if correct, False if not 
  26. "" 
  27. guess = f'{last_proof}{proof}'.encode()  
  28. guess_hash = hashlib.sha256(guess).hexdigest()  
  29. return guess_hash[:4] == "0000"  

要调整算法的难度,我们可以修改前导零的数量。但是4就足够了。您会发现,添加单个前导零会极大地缩短寻找解决方案所需的时间。

我们的类快要完成了,我们已经准备好开始使用HTTP请求与其进行交互。

步骤2:我们的区块链作为API

我们将使用Python Flask框架。这是一个微框架,可轻松将端点映射到Python函数。这使我们可以使用HTTP请求通过web与区块链进行通信。

我们将创建三种方法:

  • /transactions/new 创建一个新的交易块。
  • /mine 告诉我们的服务器挖掘一个新块。
  • /chain 返回完整的区块链。

设置Flask

我们的“服务器”将在我们的区块链网络中形成单个节点。让我们创建一个demo:

  1. import hashlib  
  2. import json  
  3. from textwrap import dedent  
  4. from time import time  
  5. from uuid import uuid4  
  6. from flask import Flask  
  7. class Blockchain(object):  
  8. ...  
  9. # Instantiate our Node  
  10. app = Flask(__name__)  
  11. # Generate a globally unique address for this node  
  12. node_identifier = str(uuid4()).replace('-''' 
  13. # Instantiate the Blockchain  
  14. blockchain = Blockchain()  
  15. @app.route('/mine', methods=['GET'])  
  16. def mine():  
  17. return "We'll mine a new Block"  
  18. @app.route('/transactions/new', methods=['POST'])  
  19. def new_transaction():  
  20. return "We'll add a new transaction"  
  21. @app.route('/chain', methods=['GET'])  
  22. def full_chain():  
  23. response = {  
  24. 'chain': blockchain.chain,  
  25. 'length': len(blockchain.chain),  
  26.  
  27. return jsonify(response), 200  
  28. if __name__ == '__main__' 
  29. app.run(host='0.0.0.0', port=5000)  

简要说明:

  • 第15行:实例化我们的节点;太阳城娱乐网最快登入Flask更多信息
  • 第18行:为节点创建一个随机名称。
  • 第21行:实例化Blockchain类。
  • 第24–26行:创建/mine端点,这是一个GET请求。
  • 第28–30行:创建/transactions/new端点,这是一个POST请求,因为我们将向它发送数据。
  • 第32–38行:创建/chain端点,该端点返回完整的区块链。
  • 40-41行:在端口5000上运行服务器。

交易端点

这就是交易请求的样子。这是用户发送到服务器的内容:

  1.  
  2. "sender""my address" 
  3. "recipient""someone else's address" 
  4. "amount": 5  
  5.  

由于我们已经有了用于将事务添加到块中的类方法,因此其余操作很简单。让我们编写添加事务的函数:

  1. import hashlib  
  2. import json  
  3. from textwrap import dedent  
  4. from time import time  
  5. from uuid import uuid4  
  6. from flask import Flask, jsonify, request  
  7. ...  
  8. @app.route('/transactions/new', methods=['POST'])  
  9. def new_transaction():  
  10. values = request.get_json()  
  11. Check that the required fields are in the POST'ed data  
  12. required = ['sender''recipient''amount' 
  13. if not all(k in values for k in required):  
  14. return 'Missing values', 400  
  15. Create a new Transaction  
  16. index = blockchain.new_transaction(values['sender'], values['recipient'], values['amount'])  
  17. response = {'message': f'Transaction will be added to Block {index}' 
  18. return jsonify(response), 201  

创建交易的方法

挖矿端点

我们的挖矿终点是奇迹发生的地方,这很容易上手。

它必须做三件事:

  1. 计算工作量证明
  2. 奖励矿商(我们)通过增加一个交易给予我们1枚硬币
  3. 将新的区块上链 
  1. import hashlib  
  2. import json  
  3. from time import time  
  4. from uuid import uuid4  
  5. from flask import Flask, jsonify, request  
  6. ...  
  7. @app.route('/mine', methods=['GET'])  
  8. def mine():  
  9. # We run the proof of work algorithm to get the next proof...  
  10. last_block = blockchain.last_block  
  11. last_proof = last_block['proof' 
  12. proof = blockchain.proof_of_work(last_proof)  
  13. # We must receive a reward for finding the proof.  
  14. # The sender is "0" to signify that this node has mined a new coin.  
  15. blockchain.new_transaction(  
  16. sender="0" 
  17. recipient=node_identifier,  
  18. amount=1,  
  19.  
  20. # Forge the new Block by adding it to the chain  
  21. previous_hash = blockchain.hash(last_block)  
  22. block = blockchain.new_block(proof, previous_hash)  
  23. response = {  
  24. 'message'"New Block Forged" 
  25. 'index': block['index'],  
  26. 'transactions': block['transactions'],  
  27. 'proof': block['proof'],  
  28. 'previous_hash': block['previous_hash'],  
  29.  
  30. return jsonify(response), 200  

注意,已开采区块的接收者是我们节点的地址。而且,我们在这里所做的大部分工作只是与Blockchain类上的方法进行交互。至此,我们已经完成,可以开始与区块链进行交互了。

步骤3:与区块链交互

您可以使用普通的旧cURL或Postman通过网络与我们的API进行交互。

启动服务器:

  1. $ python blockchain.py 
  2. * Running on /127_0_0_1:5000/ (按CTRL + C退出)  

让我们尝试通过向/localhost:5000/mine:发出GET请求来挖掘一个块:

使用邮递员发出GET请求让我们创建一个新的事务,通过发送POST请求到/localhost:5000/transactions/new,其主体包含我们的事务结构:

使用邮递员发出POST请求

如果您不使用Postman,可以使用cURL发出等效请求:/localhost:5000/chain:

  1.  
  2. "chain": [  
  3.  
  4. "index": 1,  
  5. "previous_hash": 1,  
  6. "proof": 100,  
  7. "timestamp": 1506280650.770839,  
  8. "transactions": []  
  9. },  
  10.  
  11. "index": 2,  
  12. "previous_hash""c099bc...bfb7" 
  13. "proof": 35293,  
  14. "timestamp": 1506280664.717925,  
  15. "transactions": [  
  16.  
  17. "amount": 1,  
  18. "recipient""8bbcb347e0634905b0cac7955bae152b" 
  19. "sender""0"  
  20.  
  21.  
  22. },  
  23.  
  24. "index": 3,  
  25. "previous_hash""eff91a...10f2" 
  26. "proof": 35089,  
  27. "timestamp": 1506280666.1086972,  
  28. "transactions": [  
  29.  
  30. "amount": 1,  
  31. "recipient""8bbcb347e0634905b0cac7955bae152b" 
  32. "sender""0"  
  33.  
  34.  
  35.  
  36. ],  
  37. "length": 3  
  38.  

步骤4:共识

我们目前已经拥有一个基本的区块链,可以接受交易并允许我们挖掘新的区块。但是区块链的重点在于它们应该去中心化。而且,如果它们是去中心,我们如何确保它们都反映相同的链?这叫做共识问题,如果我们要在网络中拥有多个节点,就必须实现共识算法。

注册新节点

在实现共识算法之前,我们需要一种让节点知道网络上相邻节点的方法。我们网络上的每个节点都应保留网络上其他节点的注册表。

因此,我们将需要更多的端点:

  1. /nodes/register 接受URL形式的新节点列表。
  2. /nodes/resolve 实现我们的共识算法,该算法可以解决所有冲突-确保节点具有正确的链。

我们需要修改区块链的构造函数,并提供一种注册节点的方法:

  1. ...  
  2. from urllib.parse import urlparse  
  3. ...  
  4. class Blockchain(object):  
  5. def __init__(self):  
  6. ...  
  7. self.nodes = set()  
  8. ...  
  9. def register_node(self, address): 
  10. "" 
  11. Add a new node to the list of nodes  
  12. :param address: Address of node. Eg. '/192_168_0_5:5000'  
  13. :return: None  
  14. "" 
  15. parsed_url = urlparse(address)  
  16. self.nodes.add(parsed_url.netloc)  

一种将相邻节点添加到网络的方法

请注意,我们使用了a set()来保存节点列表。这是一种廉价方法,它确保添加新节点是幂等,这意味着无论我们添加特定节点多少次,它都将只出现一次。

实施共识算法

如上所述,当一个节点与另一节点具有不同的链时会发生冲突。为了解决这个问题,我们规定最长的有效链是具有最高权威的。换句话说,网络上最长的链是事实链。使用此算法,我们可以在网络中的节点之间达成共识。

  1. ...  
  2. import requests  
  3. class Blockchain(object)  
  4. ...  
  5. def valid_chain(self, chain):  
  6. "" 
  7. Determine if a given blockchain is valid  
  8. :param chain: A blockchain  
  9. :returnTrue if valid, False if not  
  10. "" 
  11. last_block = chain[0]  
  12. current_index = 1  
  13. while current_index < len(chain):  
  14. block = chain[current_index]  
  15. print(f'{last_block}' 
  16. print(f'{block}' 
  17. print("\n-----------\n" 
  18. Check that the hash of the block is correct  
  19. if block['previous_hash'] != self.hash(last_block):  
  20. return False  
  21. Check that the Proof of Work is correct  
  22. if not self.valid_proof(last_block['proof'], block['proof']):  
  23. return False  
  24. last_block = block  
  25. current_index += 1  
  26. return True  
  27. def resolve_conflicts(self):  
  28. "" 
  29. This is our Consensus Algorithm, it resolves conflicts  
  30. by replacing our chain with the longest one in the network.  
  31. :returnTrue if our chain was replaced, False if not  
  32. "" 
  33. neighbours = self.nodes  
  34. new_chain = None  
  35. # We're only looking for chains longer than ours  
  36. max_length = len(self.chain)  
  37. # Grab and verify the chains from all the nodes in our network  
  38. for node in neighbours:  
  39. response = requests.get(f'/{node}/chain' 
  40. if response.status_code == 200:  
  41. length = response.json()['length' 
  42. chain = response.json()['chain' 
  43. Check if the length is longer and the chain is valid  
  44. if length > max_length and self.valid_chain(chain):  
  45. max_length = length  
  46. new_chain = chain  
  47. Replace our chain if we discovered a new, valid chain longer than ours  
  48. if new_chain:  
  49. self.chain = new_chain  
  50. return True  
  51. return False  

第一种方法valid_chain()负责通过检查每个块并验证哈希和检验链是否有效。

resolve_conflicts()是一种方法,它会检查我们所有的相邻节点,下载它们的链并使用上述方法验证它们。如果找到有效链,其长度大于我们的长度,我们将替换它。

让我们将两个端点注册到我们的API,一个端点用于添加相邻节点,另一个端点用于解决冲突:

  1. @app.route('/nodes/register', methods=['POST'])  
  2. def register_nodes():  
  3. values = request.get_json()  
  4. nodes = values.get('nodes' 
  5. if nodes is None:  
  6. return "Error: Please supply a valid list of nodes", 400  
  7. for node in nodes:  
  8. blockchain.register_node(node)  
  9. response = {  
  10. 'message''New nodes have been added' 
  11. 'total_nodes': list(blockchain.nodes),  
  12.  
  13. return jsonify(response), 201  
  14. @app.route('/nodes/resolve', methods=['GET'])  
  15. def consensus():  
  16. replaced = blockchain.resolve_conflicts()  
  17. if replaced:  
  18. response = {  
  19. 'message''Our chain was replaced' 
  20. 'new_chain': blockchain.chain  
  21.  
  22. else 
  23. response = {  
  24. 'message''Our chain is authoritative' 
  25. 'chain': blockchain.chain  
  26.  
  27. return jsonify(response), 200  

此时,您可以根据需要使用其他计算机,并在网络上启动不同的节点。或使用同一台计算机上的不同端口启动进程。我在机器上的另一个端口上旋转了另一个节点,并将其注册到当前节点。因此,我有两个节点:/localhost:5000和/localhost:5001。

注册新节点

然后,我在节点2上挖到了一些新区块,以确保链更长。之后,对GET /nodes/resolve在节点1上进行了调用,在该节点上,该链被共识算法替换:

工作中的共识算法

目前为止已经接近成功;可以去找一些朋友一起帮助测试您的区块链。

原文标题:Learn Blockchains by Building One,作者:Daniel van Flymen

【51CTO译稿,合作站点转载请注明原文译者和出处为太阳城娱乐网最快登入 www.2233122.com】

【编辑推荐】

  1. 太阳城娱乐网最快登入监管环境为企业探索区块链提供更多动力
  2. 区块链为什么必须要发币,发币代表着融资吗?
  3. 区块链成重要突破口,与币圈无关却与5G有关联
  4. 被新闻刷屏了的区块链 它到底是个啥?
  5. 腾讯:中国区块链公司数量连续两年增幅超250%
【责任编辑:庞桂玉 TEL:(010)68476606】

点赞 0
大家都在看
猜你喜欢

订阅专栏+更多

中间件安全防护攻略

中间件安全防护攻略

4类安全防护
共4章 | hack_man

119人订阅学习

CentOS 8 全新学习术

CentOS 8 全新学习术

CentOS 8 正式发布
共16章 | UbuntuServer

275人订阅学习

用Python玩转excel

用Python玩转excel

让重复操作傻瓜化
共3章 | DE8UG

234人订阅学习

视频课程+更多

你必学的SSM实战案例

你必学的SSM实战案例

讲师:齐毅20772人学习过

强哥带你精通zabbix监控

强哥带你精通zabbix监控

讲师:周玉强15756人学习过

NodeJS基础、Express实战视频课程【后台管理系统】【杨胜强老师-前端系列课程】

NodeJS基础、Express实战视频课程【后台管理

讲师:杨过大侠22374人学习过

读 书 +更多

Tomcat与Java Web开发技术详解

本书详细介绍了在最新Tomcat 5版本上开发Java Web应用的各种技术。主要内容包括:Tomcat和Java Web开发的基础知识,Java Web开发的高级技术...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊

51CTO服务号

51CTO官微

申博娱乐手机登入网址 电子游戏微信支付充值 www.11tyc.com 申博桌面版下载直营网 申博太阳城亚洲微信支付充值 旧版申博会员注册
菲律宾太阳网a99.com www.tyc88.com 菲律宾申博娱乐现金网 申博138代理直营网 www.sb87.com 申博娱乐城直营网
www.99msc.com 申博官网下载中心直营网 www.tyc33.com 太阳城亚洲游戏登入 新版申博开户直营网 申博现金网登入