<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[老徐]]></title>
  <link href="http://xuyao.club/atom.xml" rel="self"/>
  <link href="http://xuyao.club/"/>
  <updated>2025-11-07T16:25:18+08:00</updated>
  <id>http://xuyao.club/</id>
  <author>
    <name><![CDATA[Peter Xu]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[关于Transformer模型架构(笔记版)]]></title>
    <link href="http://xuyao.club/blog/2025/11/07/the-architecture-of-the-transformer-model/"/>
    <updated>2025-11-07T16:21:04+08:00</updated>
    <id>http://xuyao.club/blog/2025/11/07/the-architecture-of-the-transformer-model</id>
    <content type="html"><![CDATA[<p>之前在做部门技术分享的时候，给大家讲解了Transformer模型架构的原理，现把有标注版的笔记文件发出来，备份一下<br/>
<a href="https://self-yao.oss-cn-shanghai.aliyuncs.com/Transformer%E8%AE%BA%E6%96%87_recovered1_recovered.pdf">点击查看文档</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[关于旧图片]]></title>
    <link href="http://xuyao.club/blog/2025/11/07/abount-old-images/"/>
    <updated>2025-11-07T16:06:09+08:00</updated>
    <id>http://xuyao.club/blog/2025/11/07/abount-old-images</id>
    <content type="html"><![CDATA[<p>之前的图片一直存储在七牛云上，用了10来年了，去年突然收到七牛云发的邮件，提醒我已经欠费500多块钱，吓了一跳，因为我的图片数据量不多，流量也不多，再怎么用也不会出现这么多费用，何况之前充值过钱进去，排查才发现，之前blog上有一篇ppt文件被疯狂下载，花了几百G的流量，找七牛去客服，客服说没有出事情没有第一时间找他们，扣的费用只能我自己承担。。。。</p>

<p>后来因为没有缴费，图片资源被释放，账号就被冻结了。。。所以很多年前写的blog图片显示不出来。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用PyTorch构建CNN网络训练FashionMNIST数据集]]></title>
    <link href="http://xuyao.club/blog/2023/07/27/pytorch-was-used-to-build-a-cnn-network-to-train-the-fashion-mnist-dataset/"/>
    <updated>2023-07-27T16:31:49+08:00</updated>
    <id>http://xuyao.club/blog/2023/07/27/pytorch-was-used-to-build-a-cnn-network-to-train-the-fashion-mnist-dataset</id>
    <content type="html"><![CDATA[<h4>前言</h4>

<p>本文记录了使用PyTorch构建一个简单的CNN网络，并使用Fahion-MNIST数据集进行训练和测试。记录整个推理过程</p>

<!--more-->


<h4>1、Fashion-MNIST数据集</h4>

<p>Fashion-MNIST是一个流行的图像分类数据集，用于机器学习和计算机视觉任务。数据集包含了来自10个不同类别的70,000个灰度图像。每个图像的分辨率为28x28像素，并包含单件服装或配饰的图像。这些类别包括：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>1、T恤
</span><span class='line'>2、裤子
</span><span class='line'>3、毛衣
</span><span class='line'>4、裙子
</span><span class='line'>5、外套
</span><span class='line'>6、凉鞋
</span><span class='line'>7、衬衫
</span><span class='line'>8、运动鞋
</span><span class='line'>9、包
</span><span class='line'>10、短靴</span></code></pre></td></tr></table></div></figure>


<p>Fashion-MNIST数据集的目标是训练机器学习模型来准确地识别图像中的服装类别。由于这些图像是灰度图像，每个像素的值介于0到255之间。</p>

<p>该数据集通常用于测试图像分类算法的性能，以及在实践中验证新的计算机视觉技术。它与MNIST数据集类似，但更具挑战性，因为服装图像的变化更加复杂。</p>

<h4>2、构建卷积神经网络</h4>

<p>由于Fashion-MINST数据集跟MINST数据集一样，都是28*28的灰度图片，所以他们的输入是一样的，我们可以直接按照上次训练MINST的卷积神经网络来训练Fashion-MINST，上一讲中训练MINST的网络结构如下(具体可参考上一篇文章)：
Conv1->Relu->pool->Conv2->Relu->pool->Linear1->Relu->Linear2->Sofrmax
使用上一讲的卷积神经网络训练，训练10个epoch后的准确率在86%左右，可以看出，准确率不是很高，现在改一下神经网络，来提高其准确率，主要是增加卷积层，上一讲中只有两个卷积层，现在我们可以再增加一个卷积层，来看下训练效果，代码如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
<span class='line-number'>120</span>
<span class='line-number'>121</span>
<span class='line-number'>122</span>
<span class='line-number'>123</span>
<span class='line-number'>124</span>
<span class='line-number'>125</span>
<span class='line-number'>126</span>
<span class='line-number'>127</span>
<span class='line-number'>128</span>
<span class='line-number'>129</span>
<span class='line-number'>130</span>
<span class='line-number'>131</span>
<span class='line-number'>132</span>
<span class='line-number'>133</span>
<span class='line-number'>134</span>
<span class='line-number'>135</span>
<span class='line-number'>136</span>
<span class='line-number'>137</span>
<span class='line-number'>138</span>
<span class='line-number'>139</span>
<span class='line-number'>140</span>
<span class='line-number'>141</span>
<span class='line-number'>142</span>
<span class='line-number'>143</span>
<span class='line-number'>144</span>
<span class='line-number'>145</span>
<span class='line-number'>146</span>
<span class='line-number'>147</span>
<span class='line-number'>148</span>
<span class='line-number'>149</span>
<span class='line-number'>150</span>
<span class='line-number'>151</span>
<span class='line-number'>152</span>
<span class='line-number'>153</span>
<span class='line-number'>154</span>
<span class='line-number'>155</span>
<span class='line-number'>156</span>
<span class='line-number'>157</span>
<span class='line-number'>158</span>
<span class='line-number'>159</span>
<span class='line-number'>160</span>
<span class='line-number'>161</span>
<span class='line-number'>162</span>
<span class='line-number'>163</span>
<span class='line-number'>164</span>
<span class='line-number'>165</span>
<span class='line-number'>166</span>
<span class='line-number'>167</span>
<span class='line-number'>168</span>
<span class='line-number'>169</span>
<span class='line-number'>170</span>
<span class='line-number'>171</span>
<span class='line-number'>172</span>
<span class='line-number'>173</span>
<span class='line-number'>174</span>
<span class='line-number'>175</span>
<span class='line-number'>176</span>
<span class='line-number'>177</span>
<span class='line-number'>178</span>
<span class='line-number'>179</span>
<span class='line-number'>180</span>
<span class='line-number'>181</span>
<span class='line-number'>182</span>
<span class='line-number'>183</span>
<span class='line-number'>184</span>
<span class='line-number'>185</span>
<span class='line-number'>186</span>
<span class='line-number'>187</span>
<span class='line-number'>188</span>
<span class='line-number'>189</span>
<span class='line-number'>190</span>
<span class='line-number'>191</span>
<span class='line-number'>192</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>import torch
</span><span class='line'>import torch.nn as nn
</span><span class='line'>import torch.nn.functional as F
</span><span class='line'>from torchvision import datasets, transforms
</span><span class='line'>import torchvision
</span><span class='line'>from torch.autograd import Variable
</span><span class='line'>import torch.optim as optim
</span><span class='line'>import matplotlib.pyplot as plt
</span><span class='line'>import sys
</span><span class='line'>
</span><span class='line'>BATCH_SIZE = 200 #每单次训练时加载的数据量，如果是用GPU跑的话，可以设置得高一点。
</span><span class='line'>EPOCHS = 5  # 总共训练批次
</span><span class='line'>DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")  # 让torch判断是否使用GPU，建议使用GPU环境，因为会快很多
</span><span class='line'>
</span><span class='line'>train_loader = torch.utils.data.DataLoader(
</span><span class='line'>    datasets.FashionMNIST('../datasets/data', train=True, download=True,
</span><span class='line'>                   transform=transforms.Compose([
</span><span class='line'>                       transforms.ToTensor(),
</span><span class='line'>                       transforms.Normalize(mean=[0.5],std=[0.5])  # transforms.Normalize()将数据进行归一化处理，
</span><span class='line'>                   ])),
</span><span class='line'>    batch_size=BATCH_SIZE, shuffle=True)
</span><span class='line'>
</span><span class='line'>test_loader = torch.utils.data.DataLoader(
</span><span class='line'>    datasets.FashionMNIST('../datasets/data', train=False, transform=transforms.Compose([
</span><span class='line'>        transforms.ToTensor(),
</span><span class='line'>        transforms.Normalize(mean=[0.5],std=[0.5])
</span><span class='line'>    ])),
</span><span class='line'>    batch_size=BATCH_SIZE, shuffle=True)
</span><span class='line'>
</span><span class='line'># Class labels
</span><span class='line'>classes = ('T恤', '牛仔裤', '毛衣', '裙子', '外套',
</span><span class='line'>        '凉鞋', '衬衫', '运动鞋', '包', '短靴')
</span><span class='line'>
</span><span class='line'># 网络结构 conv-&gt;Relu-&gt;pool-&gt;conv-&gt;Relu-&gt;pool-&gt;Linear-&gt;Relu-&gt;Linear-&gt;Sofrmax
</span><span class='line'>class MNISTConvNet(nn.Module):
</span><span class='line'>  def __init__(self):
</span><span class='line'>    super().__init__()
</span><span class='line'>    # 公式：OH=(H + 2P - FH)/S + 1; OW= (W + 2P - FW)/S + 1
</span><span class='line'>    self.conv1 = nn.Conv2d(in_channels=1, out_channels=24, kernel_size=3, stride=1, padding=0) # 12, 26*26
</span><span class='line'>    self.conv2 = nn.Conv2d(in_channels=24, out_channels=48, kernel_size=3, stride=1, padding=0) # 24, 24*24
</span><span class='line'>    self.conv3 = nn.Conv2d(in_channels=48, out_channels=96, kernel_size=3, stride=1, padding=0) # 48, 10*10
</span><span class='line'>    self.fc1 = nn.Linear(in_features=96*5*5, out_features=400)
</span><span class='line'>    self.fc2 = nn.Linear(in_features=400, out_features=10)
</span><span class='line'>    
</span><span class='line'>  def forward(self, x):
</span><span class='line'>    out = self.conv1(x)
</span><span class='line'>    out = F.relu(out)
</span><span class='line'>    # out = F.max_pool2d(input=out, kernel_size=(2,2), stride=2) #12 13*13
</span><span class='line'>    
</span><span class='line'>    out = self.conv2(out)
</span><span class='line'>    out = F.relu(out)
</span><span class='line'>    out = F.max_pool2d(input=out, kernel_size=(2,2), stride=2) #24 12*12
</span><span class='line'>    
</span><span class='line'>    out = self.conv3(out)
</span><span class='line'>    out = F.relu(out)
</span><span class='line'>    out = F.max_pool2d(input=out, kernel_size=(2,2), stride=2) #48 5*5
</span><span class='line'>    
</span><span class='line'>    out = out.view(-1,96*5*5)
</span><span class='line'>    out = self.fc1(out)
</span><span class='line'>    out = F.relu(out)
</span><span class='line'>    
</span><span class='line'>    out = self.fc2(out)
</span><span class='line'>    
</span><span class='line'>    out = F.log_softmax(out, dim=1)
</span><span class='line'>    return out
</span><span class='line'>
</span><span class='line'>def train(model, optimizer, epoch):
</span><span class='line'>  model.train() #设置模型为训练模式
</span><span class='line'>  train_loss = 0
</span><span class='line'>  correct = 0
</span><span class='line'>  for batch_id, (images, labels) in enumerate(train_loader):
</span><span class='line'>    images = images.to(DEVICE) # 将tensors移动到配置的device
</span><span class='line'>    labels = labels.to(DEVICE)
</span><span class='line'>    optimizer.zero_grad()  # 在反向传播的时候先把梯度记录清0
</span><span class='line'>    output = model(images)
</span><span class='line'>    loss = F.nll_loss(output, labels)
</span><span class='line'>    loss.backward()
</span><span class='line'>    optimizer.step()  # 调用step()方法更新梯度参数
</span><span class='line'>    if (batch_id + 1) % 30 == 0:
</span><span class='line'>        print(f'Train Epoch: {epoch} [{batch_id * len(images)}/{len(train_loader.dataset)} ({ 100. * batch_id / len(train_loader):.0f}%)]\tLoss: {loss.item()}')
</span><span class='line'>    train_loss += loss.item()
</span><span class='line'>    # print(f'train loss: {loss.item()}, train_loss_sum: {train_loss}')
</span><span class='line'>    
</span><span class='line'>    pred = output.max(1, keepdim=True)[1]  # 找到概率最大的下标
</span><span class='line'>    correct += pred.eq(labels.view_as(pred)).sum().item()
</span><span class='line'>  return 100. * train_loss / len(train_loader.dataset), 100. * correct / len(train_loader.dataset)
</span><span class='line'>  
</span><span class='line'>def test(model):
</span><span class='line'>  model.eval()
</span><span class='line'>  test_loss = 0
</span><span class='line'>  correct = 0
</span><span class='line'>  with torch.no_grad():  # 禁用梯度计算，验证模式一般不需要进行梯度更新及反向传播，所以不需要更新梯度参数
</span><span class='line'>      for images, labels in test_loader:
</span><span class='line'>          images, labels = images.to(DEVICE), labels.to(DEVICE)
</span><span class='line'>          output = model(images)
</span><span class='line'>          test_loss += F.nll_loss(output, labels, reduction='sum').item()  # 将一批的损失相加
</span><span class='line'>          pred = output.max(1, keepdim=True)[1]  # 找到概率最大的下标
</span><span class='line'>          correct += pred.eq(labels.view_as(pred)).sum().item()
</span><span class='line'>
</span><span class='line'>  test_loss /= len(test_loader.dataset)
</span><span class='line'>  print(f'\nTest set: Average loss: {test_loss:.4f}, Accuracy: {correct}/{len(test_loader.dataset)} ({100. * correct / len(test_loader.dataset)}%)\n')
</span><span class='line'>  return test_loss, 100. * correct / len(test_loader.dataset)
</span><span class='line'>
</span><span class='line'>def predict(model):
</span><span class='line'>  val_loader = torch.utils.data.DataLoader(
</span><span class='line'>    datasets.FashionMNIST('../datasets/data', train=False, transform=transforms.Compose([
</span><span class='line'>                       transforms.ToTensor(),
</span><span class='line'>                       transforms.Normalize(mean=[0.5],std=[0.5])
</span><span class='line'>                   ])),batch_size=8, shuffle=True)
</span><span class='line'>  iterator = iter(val_loader)#获得Iterator对象:
</span><span class='line'>  X_val, Y_val = next(iterator) #循环Iterator对象迭代器，一般和上面的iter()一起使用
</span><span class='line'>  inputs = Variable(X_val)
</span><span class='line'>  #Variable()函数用于将一个张量转换为可训练的变量(也称为梯度变量)。使用Variable()函数可以方便地更新神经网络中的参数，从而实现反向传播算法。
</span><span class='line'>  pred = model(inputs)
</span><span class='line'>  _,pred = torch.max(pred, 1) #找到 tensor里最大的值，torch.max(input, dim)，input是softmax函数输出的一个tensor。 dim是max函数索引的维度0/1，0是每列的最大值，1是每行的最大值
</span><span class='line'>  print("实际结果:",[classes[i] for i in Y_val])
</span><span class='line'>  print("推理结果:", [ classes[i] for i in pred.data])
</span><span class='line'>
</span><span class='line'>  img = torchvision.utils.make_grid(X_val)
</span><span class='line'>  img = img.numpy().transpose(1,2,0)
</span><span class='line'>
</span><span class='line'>  std = [0.5,0.5,0.5] #标准差，用于计算标准化后的每个通道的值。
</span><span class='line'>  mean = [0.5,0.5,0.5] #均值，用于计算标准化后的每个通道的值。
</span><span class='line'>  img = img*std+mean
</span><span class='line'>  plt.imshow(img)
</span><span class='line'>  plt.show()
</span><span class='line'>  
</span><span class='line'>
</span><span class='line'>def run_train():
</span><span class='line'>  model = MNISTConvNet().to(DEVICE)
</span><span class='line'>  optimizer = optim.Adam(model.parameters()) #Adam方法更新权重参数
</span><span class='line'>  # optimizer = optim.SGD(model.parameters(), lr=1e-1, momentum = 0.9) #SGD方法更新权重参数,学习率设置大一点，过小梯度下降过慢
</span><span class='line'>  train_loss_list, test_loss_list = [],[]
</span><span class='line'>  train_acc_list, test_acc_list = [],[]
</span><span class='line'>  for epoch in range(1, EPOCHS + 1):
</span><span class='line'>    train_loss, train_acc =  train(model, optimizer, epoch)
</span><span class='line'>    #torch.save(model.state_dict(), 'fashion_mnist_model.pkl') #保存模型
</span><span class='line'>    test_loss, test_acc = test(model)
</span><span class='line'>    train_acc_list.append(train_acc)
</span><span class='line'>    test_acc_list.append(test_acc)
</span><span class='line'>    train_loss_list.append(train_loss)
</span><span class='line'>    test_loss_list.append(test_loss)
</span><span class='line'>    print(f'Epoch: {epoch} Train Loss: {train_loss:.4f}, Train Acc.: {train_acc:.2f}% | Validation Loss: {test_loss:.4f}, Validation Acc.: {test_acc:.2f}%')
</span><span class='line'>  
</span><span class='line'>  plt.plot(range(1, EPOCHS+1), train_loss_list, label='Training loss')
</span><span class='line'>  plt.plot(range(1, EPOCHS+1), test_loss_list, label='Validation loss')
</span><span class='line'>  plt.legend(loc='upper right')
</span><span class='line'>  plt.ylabel('Cross entropy')
</span><span class='line'>  plt.xlabel('Epoch')
</span><span class='line'>  plt.show()
</span><span class='line'>  
</span><span class='line'>
</span><span class='line'>def run_predict():
</span><span class='line'>  model = MNISTConvNet().to(DEVICE)
</span><span class='line'>  model.load_state_dict(torch.load('fashion_mnist_model.pkl')) #加载之前训练好的模型
</span><span class='line'>  predict(model)
</span><span class='line'>
</span><span class='line'>def show_image():
</span><span class='line'>  train_loader = torch.utils.data.DataLoader(
</span><span class='line'>    datasets.FashionMNIST('../datasets/data', train=True, download=True,
</span><span class='line'>                   transform=transforms.Compose([
</span><span class='line'>                       transforms.ToTensor(),
</span><span class='line'>                       transforms.Normalize((0.1307,), (0.3081,))  # transforms.Normalize()将数据进行归一化处理，
</span><span class='line'>                   ])),
</span><span class='line'>    batch_size=64, shuffle=True)
</span><span class='line'>  X_train, Y_train = next(iter(train_loader)) #循环Iterator对象迭代器，一般和上面的iter()一起使用
</span><span class='line'>  print("Image Label is:",[i for i in Y_train])
</span><span class='line'>
</span><span class='line'>  img = torchvision.utils.make_grid(X_train)
</span><span class='line'>  img = img.numpy().transpose(1,2,0)
</span><span class='line'>
</span><span class='line'>  std = [0.5,0.5,0.5] #标准差，用于计算标准化后的每个通道的值。
</span><span class='line'>  mean = [0.5,0.5,0.5] #均值，用于计算标准化后的每个通道的值。
</span><span class='line'>  img = img*std+mean
</span><span class='line'>  plt.imshow(img)
</span><span class='line'>  plt.show()
</span><span class='line'>
</span><span class='line'>if __name__ == '__main__':
</span><span class='line'>  if len(sys.argv) &lt;= 1:
</span><span class='line'>    print("请输入参数：train|predict|img") #train:表示训练数据，predict#表示推理，#img只是单纯地显示一下图片
</span><span class='line'>  else:
</span><span class='line'>    action = sys.argv[1]
</span><span class='line'>    if action == "train":
</span><span class='line'>      run_train() # 用于训练数据
</span><span class='line'>    elif action == "predict":
</span><span class='line'>      print("-----")
</span><span class='line'>      run_predict() # 用于预测图片
</span><span class='line'>    elif action == "img":
</span><span class='line'>      show_image() # 只是简单地显示图片
</span><span class='line'>    else:
</span><span class='line'>      print("请输入参数：train|predict|img")
</span><span class='line'>  
</span></code></pre></td></tr></table></div></figure>


<p>可以看到与上一讲的MINST网络的主要区别是增加一个卷积层。</p>

<h5>3、训练</h5>

<p>运行10epoch后的训练结果如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>Train Epoch: 1 [5800/60000 (10%)] Loss: 0.6379690766334534
</span><span class='line'>Train Epoch: 1 [11800/60000 (20%)]  Loss: 0.5845944881439209
</span><span class='line'>Train Epoch: 1 [17800/60000 (30%)]  Loss: 0.4599098265171051
</span><span class='line'>Train Epoch: 1 [23800/60000 (40%)]  Loss: 0.512351393699646
</span><span class='line'>Train Epoch: 1 [29800/60000 (50%)]  Loss: 0.40181490778923035
</span><span class='line'>Train Epoch: 1 [35800/60000 (60%)]  Loss: 0.3760054409503937
</span><span class='line'>Train Epoch: 1 [41800/60000 (70%)]  Loss: 0.36197417974472046
</span><span class='line'>Train Epoch: 1 [47800/60000 (80%)]  Loss: 0.3655475676059723
</span><span class='line'>Train Epoch: 1 [53800/60000 (90%)]  Loss: 0.40860098600387573
</span><span class='line'>Train Epoch: 1 [59800/60000 (100%)] Loss: 0.38368210196495056
</span><span class='line'>Train Epoch: 2 [5800/60000 (10%)] Loss: 0.3502006232738495
</span><span class='line'>Train Epoch: 2 [11800/60000 (20%)]  Loss: 0.2745484411716461
</span><span class='line'>Train Epoch: 2 [17800/60000 (30%)]  Loss: 0.29497388005256653
</span><span class='line'>Train Epoch: 2 [23800/60000 (40%)]  Loss: 0.30289018154144287
</span><span class='line'>Train Epoch: 2 [29800/60000 (50%)]  Loss: 0.3070503771305084
</span><span class='line'>Train Epoch: 2 [35800/60000 (60%)]  Loss: 0.34184956550598145
</span><span class='line'>Train Epoch: 2 [41800/60000 (70%)]  Loss: 0.25298836827278137
</span><span class='line'>Train Epoch: 2 [47800/60000 (80%)]  Loss: 0.2620333731174469
</span><span class='line'>Train Epoch: 2 [53800/60000 (90%)]  Loss: 0.2306962013244629
</span><span class='line'>Train Epoch: 2 [59800/60000 (100%)] Loss: 0.3607088327407837
</span><span class='line'>Train Epoch: 3 [5800/60000 (10%)] Loss: 0.22903680801391602
</span><span class='line'>Train Epoch: 3 [11800/60000 (20%)]  Loss: 0.20266905426979065
</span><span class='line'>Train Epoch: 3 [17800/60000 (30%)]  Loss: 0.25112783908843994
</span><span class='line'>Train Epoch: 3 [23800/60000 (40%)]  Loss: 0.22732162475585938
</span><span class='line'>Train Epoch: 3 [29800/60000 (50%)]  Loss: 0.2040642946958542
</span><span class='line'>Train Epoch: 3 [35800/60000 (60%)]  Loss: 0.20411935448646545
</span><span class='line'>Train Epoch: 3 [41800/60000 (70%)]  Loss: 0.19729731976985931
</span><span class='line'>Train Epoch: 3 [47800/60000 (80%)]  Loss: 0.24248278141021729
</span><span class='line'>Train Epoch: 3 [53800/60000 (90%)]  Loss: 0.21713067591190338
</span><span class='line'>Train Epoch: 3 [59800/60000 (100%)] Loss: 0.21899420022964478
</span><span class='line'>Train Epoch: 4 [5800/60000 (10%)] Loss: 0.1833008974790573
</span><span class='line'>Train Epoch: 4 [11800/60000 (20%)]  Loss: 0.1431916356086731
</span><span class='line'>Train Epoch: 4 [17800/60000 (30%)]  Loss: 0.2693891227245331
</span><span class='line'>Train Epoch: 4 [23800/60000 (40%)]  Loss: 0.21619722247123718
</span><span class='line'>Train Epoch: 4 [29800/60000 (50%)]  Loss: 0.22982168197631836
</span><span class='line'>Train Epoch: 4 [35800/60000 (60%)]  Loss: 0.26103365421295166
</span><span class='line'>Train Epoch: 4 [41800/60000 (70%)]  Loss: 0.23812612891197205
</span><span class='line'>Train Epoch: 4 [47800/60000 (80%)]  Loss: 0.25694453716278076
</span><span class='line'>Train Epoch: 4 [53800/60000 (90%)]  Loss: 0.2516362965106964
</span><span class='line'>Train Epoch: 4 [59800/60000 (100%)] Loss: 0.19944973289966583
</span><span class='line'>Train Epoch: 5 [5800/60000 (10%)] Loss: 0.20240060985088348
</span><span class='line'>Train Epoch: 5 [11800/60000 (20%)]  Loss: 0.17876243591308594
</span><span class='line'>Train Epoch: 5 [17800/60000 (30%)]  Loss: 0.1623563915491104
</span><span class='line'>Train Epoch: 5 [23800/60000 (40%)]  Loss: 0.14842358231544495
</span><span class='line'>Train Epoch: 5 [29800/60000 (50%)]  Loss: 0.1817866861820221
</span><span class='line'>Train Epoch: 5 [35800/60000 (60%)]  Loss: 0.1474132388830185
</span><span class='line'>Train Epoch: 5 [41800/60000 (70%)]  Loss: 0.20310136675834656
</span><span class='line'>Train Epoch: 5 [47800/60000 (80%)]  Loss: 0.2332427054643631
</span><span class='line'>Train Epoch: 5 [53800/60000 (90%)]  Loss: 0.14285261929035187
</span><span class='line'>Train Epoch: 5 [59800/60000 (100%)] Loss: 0.16876384615898132
</span><span class='line'>Train Epoch: 6 [5800/60000 (10%)] Loss: 0.15261796116828918
</span><span class='line'>Train Epoch: 6 [11800/60000 (20%)]  Loss: 0.12889760732650757
</span><span class='line'>Train Epoch: 6 [17800/60000 (30%)]  Loss: 0.17289716005325317
</span><span class='line'>Train Epoch: 6 [23800/60000 (40%)]  Loss: 0.12383649498224258
</span><span class='line'>Train Epoch: 6 [29800/60000 (50%)]  Loss: 0.14670918881893158
</span><span class='line'>Train Epoch: 6 [35800/60000 (60%)]  Loss: 0.20221909880638123
</span><span class='line'>Train Epoch: 6 [41800/60000 (70%)]  Loss: 0.21042735874652863
</span><span class='line'>Train Epoch: 6 [47800/60000 (80%)]  Loss: 0.16009800136089325
</span><span class='line'>Train Epoch: 6 [53800/60000 (90%)]  Loss: 0.23655852675437927
</span><span class='line'>Train Epoch: 6 [59800/60000 (100%)] Loss: 0.1507928967475891
</span><span class='line'>Train Epoch: 7 [5800/60000 (10%)] Loss: 0.16259260475635529
</span><span class='line'>Train Epoch: 7 [11800/60000 (20%)]  Loss: 0.14753393828868866
</span><span class='line'>Train Epoch: 7 [17800/60000 (30%)]  Loss: 0.15315169095993042
</span><span class='line'>Train Epoch: 7 [23800/60000 (40%)]  Loss: 0.1445481777191162
</span><span class='line'>Train Epoch: 7 [29800/60000 (50%)]  Loss: 0.132000133395195
</span><span class='line'>Train Epoch: 7 [35800/60000 (60%)]  Loss: 0.09024682641029358
</span><span class='line'>Train Epoch: 7 [41800/60000 (70%)]  Loss: 0.15115217864513397
</span><span class='line'>Train Epoch: 7 [47800/60000 (80%)]  Loss: 0.1311248242855072
</span><span class='line'>Train Epoch: 7 [53800/60000 (90%)]  Loss: 0.10016605257987976
</span><span class='line'>Train Epoch: 7 [59800/60000 (100%)] Loss: 0.12980304658412933
</span><span class='line'>Train Epoch: 8 [5800/60000 (10%)] Loss: 0.12055137008428574
</span><span class='line'>Train Epoch: 8 [11800/60000 (20%)]  Loss: 0.0916302502155304
</span><span class='line'>Train Epoch: 8 [17800/60000 (30%)]  Loss: 0.14020071923732758
</span><span class='line'>Train Epoch: 8 [23800/60000 (40%)]  Loss: 0.1205180287361145
</span><span class='line'>Train Epoch: 8 [29800/60000 (50%)]  Loss: 0.1326950639486313
</span><span class='line'>Train Epoch: 8 [35800/60000 (60%)]  Loss: 0.19008560478687286
</span><span class='line'>Train Epoch: 8 [41800/60000 (70%)]  Loss: 0.1668577790260315
</span><span class='line'>Train Epoch: 8 [47800/60000 (80%)]  Loss: 0.1530739814043045
</span><span class='line'>Train Epoch: 8 [53800/60000 (90%)]  Loss: 0.13995856046676636
</span><span class='line'>Train Epoch: 8 [59800/60000 (100%)] Loss: 0.05448155477643013
</span><span class='line'>Train Epoch: 9 [5800/60000 (10%)] Loss: 0.09004207700490952
</span><span class='line'>Train Epoch: 9 [11800/60000 (20%)]  Loss: 0.08474709838628769
</span><span class='line'>Train Epoch: 9 [17800/60000 (30%)]  Loss: 0.12305212020874023
</span><span class='line'>Train Epoch: 9 [23800/60000 (40%)]  Loss: 0.08823414891958237
</span><span class='line'>Train Epoch: 9 [29800/60000 (50%)]  Loss: 0.07393839210271835
</span><span class='line'>Train Epoch: 9 [35800/60000 (60%)]  Loss: 0.11944027245044708
</span><span class='line'>Train Epoch: 9 [41800/60000 (70%)]  Loss: 0.086588054895401
</span><span class='line'>Train Epoch: 9 [47800/60000 (80%)]  Loss: 0.08738173544406891
</span><span class='line'>Train Epoch: 9 [53800/60000 (90%)]  Loss: 0.1982622593641281
</span><span class='line'>Train Epoch: 9 [59800/60000 (100%)] Loss: 0.11448238044977188
</span><span class='line'>Train Epoch: 10 [5800/60000 (10%)]  Loss: 0.0850382074713707
</span><span class='line'>Train Epoch: 10 [11800/60000 (20%)] Loss: 0.06795746088027954
</span><span class='line'>Train Epoch: 10 [17800/60000 (30%)] Loss: 0.1085655689239502
</span><span class='line'>Train Epoch: 10 [23800/60000 (40%)] Loss: 0.05534665286540985
</span><span class='line'>Train Epoch: 10 [29800/60000 (50%)] Loss: 0.09382271021604538
</span><span class='line'>Train Epoch: 10 [35800/60000 (60%)] Loss: 0.026057429611682892
</span><span class='line'>Train Epoch: 10 [41800/60000 (70%)] Loss: 0.07035879790782928
</span><span class='line'>Train Epoch: 10 [47800/60000 (80%)] Loss: 0.1626715511083603
</span><span class='line'>Train Epoch: 10 [53800/60000 (90%)] Loss: 0.08846493810415268
</span><span class='line'>Train Epoch: 10 [59800/60000 (100%)]  Loss: 0.07113683223724365
</span><span class='line'>
</span><span class='line'>Test set: Average loss: 0.2453, Accuracy: 9204/10000 (92.04%)</span></code></pre></td></tr></table></div></figure>


<p>可以看到现在准确率达到了92.04%，可见适当增加卷积层可以提高识别精度</p>

<h4>4、预测</h4>

<p>使用命令预测一下</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'> python fashion_mnist_conv_net.py predict</span></code></pre></td></tr></table></div></figure>


<p><img src="http://blog.1nongfu.com/16871595198847.jpg" alt="" /></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>实际结果: ['裙子', '外套', '凉鞋', '包', '包', '毛衣', '牛仔裤', '运动鞋']
</span><span class='line'>推理结果: ['裙子', '外套', '凉鞋', '包', '包', '毛衣', '牛仔裤', '运动鞋']
</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用PyTorch构建CNN网络训练MNIST数据集]]></title>
    <link href="http://xuyao.club/blog/2023/05/26/pytorch-was-used-to-build-a-cnn-network-to-train-the-mnist-dataset/"/>
    <updated>2023-05-26T00:00:52+08:00</updated>
    <id>http://xuyao.club/blog/2023/05/26/pytorch-was-used-to-build-a-cnn-network-to-train-the-mnist-dataset</id>
    <content type="html"><![CDATA[<h4>前言</h4>

<p>本文记录了使用PyTorch构建一个简单的CNN网络，并使用MNIST数据集进行训练和测试。记录整个推理过程</p>

<h4>1、MNIST数据集</h4>

<p>MNIST数据集是一个手写数字识别数据集，包含了60,000个28x28像素的手写数字图像（灰度图片），每个数字都有10个训练样本和10个测试样本。该数据集由C. E. Mnih等人于1999年首次发布，并被广泛应用于机器学习领域的分类、识别和生成模型的研究中。<br/>
MNIST数据集的特点：</p>

<p>  1、 每个数字都是手写的，因此具有一定的噪声和不规则性；<br/>
  2、 每个数字只有一种写法，因此可以视为二元分类问题；<br/>
  3、 数据集中的数字图像比较简单，易于处理和识别；<br/>
  4、 数据集中的数字图像没有标签，需要通过预处理和特征提取等方法来自动识别。</p>

<!--more-->


<p></p>

<h4>2、构建卷积神经网络</h4>

<p>整个神经网络一共5层，2个卷积层，2个线性层，1个全链接输出层,如下：<br/>
Conv1->Relu->pool->Conv2->Relu->pool->Linear1->Relu->Linear2->Sofrmax
网络架构的说明：</p>

<p>1、因为MNIST数据是一个灰度的28<em>28的图片，所以数据输入层只有1个输入通道。<br/>
2、 卷积层的卷积核都使用3</em>3大小核。<br/>
3、 权重参数使用Adam或者SGD来更新参数。<br/>
4、 使用SGD方法，经过10epoch，准确率可以达到99.16%。<br/>
代码如下</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
<span class='line-number'>120</span>
<span class='line-number'>121</span>
<span class='line-number'>122</span>
<span class='line-number'>123</span>
<span class='line-number'>124</span>
<span class='line-number'>125</span>
<span class='line-number'>126</span>
<span class='line-number'>127</span>
<span class='line-number'>128</span>
<span class='line-number'>129</span>
<span class='line-number'>130</span>
<span class='line-number'>131</span>
<span class='line-number'>132</span>
<span class='line-number'>133</span>
<span class='line-number'>134</span>
<span class='line-number'>135</span>
<span class='line-number'>136</span>
<span class='line-number'>137</span>
<span class='line-number'>138</span>
<span class='line-number'>139</span>
<span class='line-number'>140</span>
<span class='line-number'>141</span>
<span class='line-number'>142</span>
<span class='line-number'>143</span>
<span class='line-number'>144</span>
<span class='line-number'>145</span>
<span class='line-number'>146</span>
<span class='line-number'>147</span>
<span class='line-number'>148</span>
<span class='line-number'>149</span>
<span class='line-number'>150</span>
<span class='line-number'>151</span>
<span class='line-number'>152</span>
<span class='line-number'>153</span>
<span class='line-number'>154</span>
<span class='line-number'>155</span>
<span class='line-number'>156</span>
<span class='line-number'>157</span>
<span class='line-number'>158</span>
<span class='line-number'>159</span>
<span class='line-number'>160</span>
<span class='line-number'>161</span>
<span class='line-number'>162</span>
<span class='line-number'>163</span>
<span class='line-number'>164</span>
<span class='line-number'>165</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>import torch
</span><span class='line'>import torch.nn as nn
</span><span class='line'>import torch.nn.functional as F
</span><span class='line'>from torchvision import datasets, transforms
</span><span class='line'>import torchvision
</span><span class='line'>from torch.autograd import Variable
</span><span class='line'>import torch.optim as optim
</span><span class='line'>import matplotlib.pyplot as plt
</span><span class='line'>import sys
</span><span class='line'>
</span><span class='line'>BATCH_SIZE = 200 #每单次训练时加载的数据量，如果是用GPU跑的话，可以设置得高一点。
</span><span class='line'>EPOCHS = 10  # 总共训练批次
</span><span class='line'>DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")  # 让torch判断是否使用GPU，建议使用GPU环境，因为会快很多
</span><span class='line'>
</span><span class='line'>train_loader = torch.utils.data.DataLoader(
</span><span class='line'>    datasets.MNIST('../datasets/data', train=True, download=True,
</span><span class='line'>                   transform=transforms.Compose([
</span><span class='line'>                       transforms.ToTensor(),
</span><span class='line'>                       transforms.Normalize(mean=[0.5],std=[0.5])  # transforms.Normalize()将数据进行归一化处理，
</span><span class='line'>                   ])),
</span><span class='line'>    batch_size=BATCH_SIZE, shuffle=True)
</span><span class='line'>
</span><span class='line'>test_loader = torch.utils.data.DataLoader(
</span><span class='line'>    datasets.MNIST('../datasets/data', train=False, transform=transforms.Compose([
</span><span class='line'>        transforms.ToTensor(),
</span><span class='line'>        transforms.Normalize(mean=[0.5],std=[0.5])
</span><span class='line'>    ])),
</span><span class='line'>    batch_size=BATCH_SIZE, shuffle=True)
</span><span class='line'>
</span><span class='line'># 网络结构 conv-&gt;Relu-&gt;pool-&gt;conv-&gt;Relu-&gt;pool-&gt;Linear-&gt;Relu-&gt;Linear-&gt;Sofrmax
</span><span class='line'>class MNISTConvNet(nn.Module):
</span><span class='line'>  def __init__(self):
</span><span class='line'>    super().__init__()
</span><span class='line'>    # 公式：OH=(H + 2P - FH)/S + 1; OW= (W + 2P - FW)/S + 1
</span><span class='line'>    self.conv1 = nn.Conv2d(in_channels=1, out_channels=24, kernel_size=3, stride=1, padding=0) # 24, 26*26
</span><span class='line'>    self.conv2 = nn.Conv2d(in_channels=24, out_channels=48, kernel_size=3, stride=1, padding=0) # 48, 11*11
</span><span class='line'>    self.fc1 = nn.Linear(in_features=48*5*5, out_features=200)
</span><span class='line'>    self.fc2 = nn.Linear(in_features=200, out_features=10)
</span><span class='line'>    
</span><span class='line'>  def forward(self, x):
</span><span class='line'>    out = self.conv1(x)
</span><span class='line'>    out = F.relu(out)
</span><span class='line'>    out = F.max_pool2d(input=out, kernel_size=(2,2), stride=2) #24 13*13
</span><span class='line'>    
</span><span class='line'>    out = self.conv2(out)
</span><span class='line'>    out = F.relu(out)
</span><span class='line'>    out = F.max_pool2d(input=out, kernel_size=(2,2), stride=2) #48 5*5
</span><span class='line'>    
</span><span class='line'>    out = out.view(-1,48*5*5)
</span><span class='line'>    out = self.fc1(out)
</span><span class='line'>    out = F.relu(out)
</span><span class='line'>    
</span><span class='line'>    out = self.fc2(out)
</span><span class='line'>    
</span><span class='line'>    out = F.log_softmax(out, dim=1)
</span><span class='line'>    return out
</span><span class='line'>
</span><span class='line'>def train(model, optimizer, epoch):
</span><span class='line'>  model.train() #设置模型为训练模式
</span><span class='line'>  for batch_id, (images, labels) in enumerate(train_loader):
</span><span class='line'>    images = images.to(DEVICE) # 将tensors移动到配置的device
</span><span class='line'>    labels = labels.to(DEVICE)
</span><span class='line'>    optimizer.zero_grad()  # 在反向传播的时候先把梯度记录清0
</span><span class='line'>    output = model(images)
</span><span class='line'>    loss = F.nll_loss(output, labels)
</span><span class='line'>    loss.backward()
</span><span class='line'>    optimizer.step()  # 调用step()方法更新梯度参数
</span><span class='line'>    if (batch_id + 1) % 30 == 0:
</span><span class='line'>        print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {}'.format(
</span><span class='line'>            epoch, batch_id * len(images), len(train_loader.dataset),
</span><span class='line'>                    100. * batch_id / len(train_loader), loss.item()))
</span><span class='line'>
</span><span class='line'>  
</span><span class='line'>def test(model):
</span><span class='line'>  model.eval()
</span><span class='line'>  test_loss = 0
</span><span class='line'>  correct = 0
</span><span class='line'>  with torch.no_grad():  # 禁用梯度计算，验证模式一般不需要进行梯度更新及反向传播，所以不需要更新梯度参数
</span><span class='line'>      for images, labels in test_loader:
</span><span class='line'>          images, labels = images.to(DEVICE), labels.to(DEVICE)
</span><span class='line'>          output = model(images)
</span><span class='line'>          test_loss += F.nll_loss(output, labels, reduction='sum').item()  # 将一批的损失相加
</span><span class='line'>          pred = output.max(1, keepdim=True)[1]  # 找到概率最大的下标
</span><span class='line'>          correct += pred.eq(labels.view_as(pred)).sum().item()
</span><span class='line'>
</span><span class='line'>  test_loss /= len(test_loader.dataset)
</span><span class='line'>  print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({}%)\n'.format(
</span><span class='line'>      test_loss, correct, len(test_loader.dataset),
</span><span class='line'>      100. * correct / len(test_loader.dataset)))
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>def predict(model):
</span><span class='line'>  val_loader = torch.utils.data.DataLoader(
</span><span class='line'>    datasets.MNIST('../datasets/data', train=False, transform=transforms.Compose([
</span><span class='line'>                       transforms.ToTensor(),
</span><span class='line'>                       transforms.Normalize(mean=[0.5],std=[0.5])
</span><span class='line'>                   ])),batch_size=4, shuffle=True)
</span><span class='line'>  iterator = iter(val_loader)#获得Iterator对象:
</span><span class='line'>  X_val, Y_val = next(iterator) #循环Iterator对象迭代器，一般和上面的iter()一起使用
</span><span class='line'>  inputs = Variable(X_val)
</span><span class='line'>  #Variable()函数用于将一个张量转换为可训练的变量(也称为梯度变量)。使用Variable()函数可以方便地更新神经网络中的参数，从而实现反向传播算法。
</span><span class='line'>  pred = model(inputs)
</span><span class='line'>  _,pred = torch.max(pred, 1) #找到 tensor里最大的值，torch.max(input, dim)，input是softmax函数输出的一个tensor。 dim是max函数索引的维度0/1，0是每列的最大值，1是每行的最大值
</span><span class='line'>  print("实际结果:",[i for i in Y_val])
</span><span class='line'>  print("推理结果:", [ i for i in pred.data])
</span><span class='line'>
</span><span class='line'>  img = torchvision.utils.make_grid(X_val)
</span><span class='line'>  img = img.numpy().transpose(1,2,0)
</span><span class='line'>
</span><span class='line'>  std = [0.5,0.5,0.5] #标准差，用于计算标准化后的每个通道的值。
</span><span class='line'>  mean = [0.5,0.5,0.5] #均值，用于计算标准化后的每个通道的值。
</span><span class='line'>  img = img*std+mean
</span><span class='line'>  plt.imshow(img)
</span><span class='line'>  plt.show()
</span><span class='line'>  
</span><span class='line'>
</span><span class='line'>def run_train():
</span><span class='line'>  model = MNISTConvNet().to(DEVICE)
</span><span class='line'>  optimizer = optim.Adam(model.parameters()) #Adam方法更新权重参数
</span><span class='line'>  # optimizer = optim.SGD(model.parameters(), lr=1e-1, momentum = 0.9) #SGD方法更新权重参数,学习率设置大一点，过小梯度下降过慢
</span><span class='line'>
</span><span class='line'>  for epoch in range(1, EPOCHS + 1):
</span><span class='line'>    train(model, optimizer, epoch)
</span><span class='line'>    torch.save(model.state_dict(), 'mnist_model.pkl') #保存模型
</span><span class='line'>  test(model)
</span><span class='line'>  
</span><span class='line'>
</span><span class='line'>def run_predict():
</span><span class='line'>  model = MNISTConvNet().to(DEVICE)
</span><span class='line'>  model.load_state_dict(torch.load('mnist_model.pkl')) #加载之前训练好的模型
</span><span class='line'>  predict(model)
</span><span class='line'>
</span><span class='line'>def show_image():
</span><span class='line'>  train_loader = torch.utils.data.DataLoader(
</span><span class='line'>    datasets.MNIST('../datasets/data', train=True, download=True,
</span><span class='line'>                   transform=transforms.Compose([
</span><span class='line'>                       transforms.ToTensor(),
</span><span class='line'>                       transforms.Normalize((0.1307,), (0.3081,))  # transforms.Normalize()将数据进行归一化处理，
</span><span class='line'>                   ])),
</span><span class='line'>    batch_size=64, shuffle=True)
</span><span class='line'>  X_train, Y_train = next(iter(train_loader)) #循环Iterator对象迭代器，一般和上面的iter()一起使用
</span><span class='line'>  print("Image Label is:",[i for i in Y_train])
</span><span class='line'>
</span><span class='line'>  img = torchvision.utils.make_grid(X_train)
</span><span class='line'>  img = img.numpy().transpose(1,2,0)
</span><span class='line'>
</span><span class='line'>  std = [0.5,0.5,0.5] #标准差，用于计算标准化后的每个通道的值。
</span><span class='line'>  mean = [0.5,0.5,0.5] #均值，用于计算标准化后的每个通道的值。
</span><span class='line'>  img = img*std+mean
</span><span class='line'>  plt.imshow(img)
</span><span class='line'>  plt.show()
</span><span class='line'>
</span><span class='line'>if __name__ == '__main__':
</span><span class='line'>  if len(sys.argv) &lt;= 1:
</span><span class='line'>    print("请输入参数：train|predict|img") #train:表示训练数据，predict#表示推理，#img只是单纯地显示一下图片
</span><span class='line'>  else:
</span><span class='line'>    action = sys.argv[1]
</span><span class='line'>    if action == "train":
</span><span class='line'>      run_train() # 用于训练数据
</span><span class='line'>    elif action == "predict":
</span><span class='line'>      run_predict() # 用于预测图片
</span><span class='line'>    elif action == "img":
</span><span class='line'>      show_image() # 只是简单地显示图片
</span><span class='line'>    else:
</span><span class='line'>      print("请输入参数：train|predict|img")
</span></code></pre></td></tr></table></div></figure>


<h3>3、训练</h3>

<p>上面代码首先使用Adam方法理更新权重参数，经过5个epoch后，准确率可以达到99.02%，如下
训练时使用如下代码训练：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>python mnist_conv_net.py train</span></code></pre></td></tr></table></div></figure>


<p>训练日志：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>Train Epoch: 1 [5800/60000 (10%)] Loss: 0.489694
</span><span class='line'>Train Epoch: 1 [11800/60000 (20%)]  Loss: 0.211527
</span><span class='line'>Train Epoch: 1 [17800/60000 (30%)]  Loss: 0.184858
</span><span class='line'>Train Epoch: 1 [23800/60000 (40%)]  Loss: 0.161435
</span><span class='line'>Train Epoch: 1 [29800/60000 (50%)]  Loss: 0.173204
</span><span class='line'>Train Epoch: 1 [35800/60000 (60%)]  Loss: 0.124986
</span><span class='line'>Train Epoch: 1 [41800/60000 (70%)]  Loss: 0.076274
</span><span class='line'>Train Epoch: 1 [47800/60000 (80%)]  Loss: 0.053319
</span><span class='line'>Train Epoch: 1 [53800/60000 (90%)]  Loss: 0.044781
</span><span class='line'>Train Epoch: 1 [59800/60000 (100%)] Loss: 0.063047
</span><span class='line'>Train Epoch: 2 [5800/60000 (10%)] Loss: 0.077021
</span><span class='line'>Train Epoch: 2 [11800/60000 (20%)]  Loss: 0.023402
</span><span class='line'>Train Epoch: 2 [17800/60000 (30%)]  Loss: 0.050658
</span><span class='line'>Train Epoch: 2 [23800/60000 (40%)]  Loss: 0.076794
</span><span class='line'>Train Epoch: 2 [29800/60000 (50%)]  Loss: 0.058776
</span><span class='line'>Train Epoch: 2 [35800/60000 (60%)]  Loss: 0.035746
</span><span class='line'>Train Epoch: 2 [41800/60000 (70%)]  Loss: 0.093057
</span><span class='line'>Train Epoch: 2 [47800/60000 (80%)]  Loss: 0.085911
</span><span class='line'>Train Epoch: 2 [53800/60000 (90%)]  Loss: 0.066878
</span><span class='line'>Train Epoch: 2 [59800/60000 (100%)] Loss: 0.120800
</span><span class='line'>Train Epoch: 3 [5800/60000 (10%)] Loss: 0.053668
</span><span class='line'>Train Epoch: 3 [11800/60000 (20%)]  Loss: 0.010750
</span><span class='line'>Train Epoch: 3 [17800/60000 (30%)]  Loss: 0.029436
</span><span class='line'>Train Epoch: 3 [23800/60000 (40%)]  Loss: 0.026253
</span><span class='line'>Train Epoch: 3 [29800/60000 (50%)]  Loss: 0.026762
</span><span class='line'>Train Epoch: 3 [35800/60000 (60%)]  Loss: 0.015479
</span><span class='line'>Train Epoch: 3 [41800/60000 (70%)]  Loss: 0.109069
</span><span class='line'>Train Epoch: 3 [47800/60000 (80%)]  Loss: 0.054719
</span><span class='line'>Train Epoch: 3 [53800/60000 (90%)]  Loss: 0.034847
</span><span class='line'>Train Epoch: 3 [59800/60000 (100%)] Loss: 0.019372
</span><span class='line'>Train Epoch: 4 [5800/60000 (10%)] Loss: 0.025633
</span><span class='line'>Train Epoch: 4 [11800/60000 (20%)]  Loss: 0.034000
</span><span class='line'>Train Epoch: 4 [17800/60000 (30%)]  Loss: 0.016235
</span><span class='line'>Train Epoch: 4 [23800/60000 (40%)]  Loss: 0.026829
</span><span class='line'>Train Epoch: 4 [29800/60000 (50%)]  Loss: 0.070490
</span><span class='line'>Train Epoch: 4 [35800/60000 (60%)]  Loss: 0.012940
</span><span class='line'>Train Epoch: 4 [41800/60000 (70%)]  Loss: 0.017831
</span><span class='line'>Train Epoch: 4 [47800/60000 (80%)]  Loss: 0.010007
</span><span class='line'>Train Epoch: 4 [53800/60000 (90%)]  Loss: 0.014664
</span><span class='line'>Train Epoch: 4 [59800/60000 (100%)] Loss: 0.039249
</span><span class='line'>Train Epoch: 5 [5800/60000 (10%)] Loss: 0.052612
</span><span class='line'>Train Epoch: 5 [11800/60000 (20%)]  Loss: 0.045722
</span><span class='line'>Train Epoch: 5 [17800/60000 (30%)]  Loss: 0.012584
</span><span class='line'>Train Epoch: 5 [23800/60000 (40%)]  Loss: 0.013080
</span><span class='line'>Train Epoch: 5 [29800/60000 (50%)]  Loss: 0.033559
</span><span class='line'>Train Epoch: 5 [35800/60000 (60%)]  Loss: 0.026182
</span><span class='line'>Train Epoch: 5 [41800/60000 (70%)]  Loss: 0.001794
</span><span class='line'>Train Epoch: 5 [47800/60000 (80%)]  Loss: 0.058093
</span><span class='line'>Train Epoch: 5 [53800/60000 (90%)]  Loss: 0.038260
</span><span class='line'>Train Epoch: 5 [59800/60000 (100%)] Loss: 0.012027
</span><span class='line'>
</span><span class='line'>Test set: Average loss: 0.0290, Accuracy: 9902/10000 (99.02%)</span></code></pre></td></tr></table></div></figure>


<p>可以再试下使用SGD来更新参数，将上面的Adam换成SGD</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>optimizer = optim.SGD(model.parameters(), lr=1e-1, momentum = 0.9) #SGD方法更新权重参数,学习率设置大一点，过小梯度下降过慢</span></code></pre></td></tr></table></div></figure>


<p>这里注意他的学习率，我一开始使用的是1e-3的学习率，结果发现梯度下降很慢，10epoch下来，loss值还有0.2多，精确度只有86%,把他改成1e-1，发现效果好很多，下面是他的训练日志：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>Train Epoch: 1 [5800/60000 (10%)] Loss: 0.6326162815093994
</span><span class='line'>Train Epoch: 1 [11800/60000 (20%)]  Loss: 0.14702695608139038
</span><span class='line'>Train Epoch: 1 [17800/60000 (30%)]  Loss: 0.11106981337070465
</span><span class='line'>Train Epoch: 1 [23800/60000 (40%)]  Loss: 0.11699119210243225
</span><span class='line'>Train Epoch: 1 [29800/60000 (50%)]  Loss: 0.08016740530729294
</span><span class='line'>Train Epoch: 1 [35800/60000 (60%)]  Loss: 0.043048132210969925
</span><span class='line'>Train Epoch: 1 [41800/60000 (70%)]  Loss: 0.07454550266265869
</span><span class='line'>Train Epoch: 1 [47800/60000 (80%)]  Loss: 0.03606884181499481
</span><span class='line'>Train Epoch: 1 [53800/60000 (90%)]  Loss: 0.018314605578780174
</span><span class='line'>Train Epoch: 1 [59800/60000 (100%)] Loss: 0.032142993062734604
</span><span class='line'>Train Epoch: 2 [5800/60000 (10%)] Loss: 0.017602885141968727
</span><span class='line'>Train Epoch: 2 [11800/60000 (20%)]  Loss: 0.02773950807750225
</span><span class='line'>Train Epoch: 2 [17800/60000 (30%)]  Loss: 0.09004029631614685
</span><span class='line'>Train Epoch: 2 [23800/60000 (40%)]  Loss: 0.02125852182507515
</span><span class='line'>Train Epoch: 2 [29800/60000 (50%)]  Loss: 0.0772605612874031
</span><span class='line'>Train Epoch: 2 [35800/60000 (60%)]  Loss: 0.03700004518032074
</span><span class='line'>Train Epoch: 2 [41800/60000 (70%)]  Loss: 0.05076766386628151
</span><span class='line'>Train Epoch: 2 [47800/60000 (80%)]  Loss: 0.03611752390861511
</span><span class='line'>Train Epoch: 2 [53800/60000 (90%)]  Loss: 0.04180872440338135
</span><span class='line'>Train Epoch: 2 [59800/60000 (100%)] Loss: 0.024729833006858826
</span><span class='line'>Train Epoch: 3 [5800/60000 (10%)] Loss: 0.08424612879753113
</span><span class='line'>Train Epoch: 3 [11800/60000 (20%)]  Loss: 0.004190818872302771
</span><span class='line'>Train Epoch: 3 [17800/60000 (30%)]  Loss: 0.035337768495082855
</span><span class='line'>Train Epoch: 3 [23800/60000 (40%)]  Loss: 0.0022824255283921957
</span><span class='line'>Train Epoch: 3 [29800/60000 (50%)]  Loss: 0.03864956274628639
</span><span class='line'>Train Epoch: 3 [35800/60000 (60%)]  Loss: 0.022920949384570122
</span><span class='line'>Train Epoch: 3 [41800/60000 (70%)]  Loss: 0.007762896828353405
</span><span class='line'>Train Epoch: 3 [47800/60000 (80%)]  Loss: 0.02902868203818798
</span><span class='line'>Train Epoch: 3 [53800/60000 (90%)]  Loss: 0.0689283162355423
</span><span class='line'>Train Epoch: 3 [59800/60000 (100%)] Loss: 0.013603786006569862
</span><span class='line'>Train Epoch: 4 [5800/60000 (10%)] Loss: 0.002816196996718645
</span><span class='line'>Train Epoch: 4 [11800/60000 (20%)]  Loss: 0.015283504500985146
</span><span class='line'>Train Epoch: 4 [17800/60000 (30%)]  Loss: 0.023883331567049026
</span><span class='line'>Train Epoch: 4 [23800/60000 (40%)]  Loss: 0.012441331520676613
</span><span class='line'>Train Epoch: 4 [29800/60000 (50%)]  Loss: 0.010721658356487751
</span><span class='line'>Train Epoch: 4 [35800/60000 (60%)]  Loss: 0.008633618243038654
</span><span class='line'>Train Epoch: 4 [41800/60000 (70%)]  Loss: 0.02001149021089077
</span><span class='line'>Train Epoch: 4 [47800/60000 (80%)]  Loss: 0.008363565430045128
</span><span class='line'>Train Epoch: 4 [53800/60000 (90%)]  Loss: 0.052691176533699036
</span><span class='line'>Train Epoch: 4 [59800/60000 (100%)] Loss: 0.0459044873714447
</span><span class='line'>Train Epoch: 5 [5800/60000 (10%)] Loss: 0.028606999665498734
</span><span class='line'>Train Epoch: 5 [11800/60000 (20%)]  Loss: 0.009156718850135803
</span><span class='line'>Train Epoch: 5 [17800/60000 (30%)]  Loss: 0.003058604197576642
</span><span class='line'>Train Epoch: 5 [23800/60000 (40%)]  Loss: 0.0006700430531054735
</span><span class='line'>Train Epoch: 5 [29800/60000 (50%)]  Loss: 0.010339883156120777
</span><span class='line'>Train Epoch: 5 [35800/60000 (60%)]  Loss: 0.02346840687096119
</span><span class='line'>Train Epoch: 5 [41800/60000 (70%)]  Loss: 0.01867305487394333
</span><span class='line'>Train Epoch: 5 [47800/60000 (80%)]  Loss: 0.00615763058885932
</span><span class='line'>Train Epoch: 5 [53800/60000 (90%)]  Loss: 0.026964306831359863
</span><span class='line'>Train Epoch: 5 [59800/60000 (100%)] Loss: 0.03355356678366661
</span><span class='line'>Train Epoch: 6 [5800/60000 (10%)] Loss: 0.0019284432055428624
</span><span class='line'>Train Epoch: 6 [11800/60000 (20%)]  Loss: 0.006681244820356369
</span><span class='line'>Train Epoch: 6 [17800/60000 (30%)]  Loss: 0.026242844760417938
</span><span class='line'>Train Epoch: 6 [23800/60000 (40%)]  Loss: 0.029215598478913307
</span><span class='line'>Train Epoch: 6 [29800/60000 (50%)]  Loss: 0.03575825318694115
</span><span class='line'>Train Epoch: 6 [35800/60000 (60%)]  Loss: 0.007471080869436264
</span><span class='line'>Train Epoch: 6 [41800/60000 (70%)]  Loss: 0.010791837237775326
</span><span class='line'>Train Epoch: 6 [47800/60000 (80%)]  Loss: 0.0031418739818036556
</span><span class='line'>Train Epoch: 6 [53800/60000 (90%)]  Loss: 0.005480702966451645
</span><span class='line'>Train Epoch: 6 [59800/60000 (100%)] Loss: 0.0001745843474054709
</span><span class='line'>Train Epoch: 7 [5800/60000 (10%)] Loss: 0.011564110405743122
</span><span class='line'>Train Epoch: 7 [11800/60000 (20%)]  Loss: 0.029219292104244232
</span><span class='line'>Train Epoch: 7 [17800/60000 (30%)]  Loss: 0.0013832019176334143
</span><span class='line'>Train Epoch: 7 [23800/60000 (40%)]  Loss: 0.012693165801465511
</span><span class='line'>Train Epoch: 7 [29800/60000 (50%)]  Loss: 0.0006698016077280045
</span><span class='line'>Train Epoch: 7 [35800/60000 (60%)]  Loss: 0.0018981300527229905
</span><span class='line'>Train Epoch: 7 [41800/60000 (70%)]  Loss: 0.010488353669643402
</span><span class='line'>Train Epoch: 7 [47800/60000 (80%)]  Loss: 0.0014791633002460003
</span><span class='line'>Train Epoch: 7 [53800/60000 (90%)]  Loss: 0.029287874698638916
</span><span class='line'>Train Epoch: 7 [59800/60000 (100%)] Loss: 0.029237637296319008
</span><span class='line'>Train Epoch: 8 [5800/60000 (10%)] Loss: 0.0069076246581971645
</span><span class='line'>Train Epoch: 8 [11800/60000 (20%)]  Loss: 0.0002714076545089483
</span><span class='line'>Train Epoch: 8 [17800/60000 (30%)]  Loss: 0.003580649383366108
</span><span class='line'>Train Epoch: 8 [23800/60000 (40%)]  Loss: 0.0044055297039449215
</span><span class='line'>Train Epoch: 8 [29800/60000 (50%)]  Loss: 0.005105248186737299
</span><span class='line'>Train Epoch: 8 [35800/60000 (60%)]  Loss: 0.013003651052713394
</span><span class='line'>Train Epoch: 8 [41800/60000 (70%)]  Loss: 0.002714156173169613
</span><span class='line'>Train Epoch: 8 [47800/60000 (80%)]  Loss: 0.0037790806964039803
</span><span class='line'>Train Epoch: 8 [53800/60000 (90%)]  Loss: 0.000915569078642875
</span><span class='line'>Train Epoch: 8 [59800/60000 (100%)] Loss: 0.0026095432695001364
</span><span class='line'>Train Epoch: 9 [5800/60000 (10%)] Loss: 0.002073458628728986
</span><span class='line'>Train Epoch: 9 [11800/60000 (20%)]  Loss: 0.005496991332620382
</span><span class='line'>Train Epoch: 9 [17800/60000 (30%)]  Loss: 0.009597436524927616
</span><span class='line'>Train Epoch: 9 [23800/60000 (40%)]  Loss: 0.0016645310679450631
</span><span class='line'>Train Epoch: 9 [29800/60000 (50%)]  Loss: 0.0006376765668392181
</span><span class='line'>Train Epoch: 9 [35800/60000 (60%)]  Loss: 0.0005055389483459294
</span><span class='line'>Train Epoch: 9 [41800/60000 (70%)]  Loss: 0.0015127335209399462
</span><span class='line'>Train Epoch: 9 [47800/60000 (80%)]  Loss: 0.0017895273631438613
</span><span class='line'>Train Epoch: 9 [53800/60000 (90%)]  Loss: 0.00020351675630081445
</span><span class='line'>Train Epoch: 9 [59800/60000 (100%)] Loss: 0.003212581854313612
</span><span class='line'>Train Epoch: 10 [5800/60000 (10%)]  Loss: 0.00015950168017297983
</span><span class='line'>Train Epoch: 10 [11800/60000 (20%)] Loss: 0.0013000047765672207
</span><span class='line'>Train Epoch: 10 [17800/60000 (30%)] Loss: 0.0015988206723704934
</span><span class='line'>Train Epoch: 10 [23800/60000 (40%)] Loss: 0.0006124568171799183
</span><span class='line'>Train Epoch: 10 [29800/60000 (50%)] Loss: 0.013285879977047443
</span><span class='line'>Train Epoch: 10 [35800/60000 (60%)] Loss: 0.00040567651740275323
</span><span class='line'>Train Epoch: 10 [41800/60000 (70%)] Loss: 0.00692130858078599
</span><span class='line'>Train Epoch: 10 [47800/60000 (80%)] Loss: 0.0020271940156817436
</span><span class='line'>Train Epoch: 10 [53800/60000 (90%)] Loss: 0.00022073769650887698
</span><span class='line'>Train Epoch: 10 [59800/60000 (100%)]  Loss: 0.002098886761814356
</span><span class='line'>
</span><span class='line'>Test set: Average loss: 0.0360, Accuracy: 9916/10000 (99.16%)</span></code></pre></td></tr></table></div></figure>


<h4>4、预测</h4>

<p>使用如下代码进行预测</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>python mnist_conv_net.py predict</span></code></pre></td></tr></table></div></figure>


<p>可以看到输出结果：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>实际结果: [tensor(8), tensor(7), tensor(4), tensor(7)]
</span><span class='line'>推理结果: [tensor(8), tensor(7), tensor(4), tensor(7)]</span></code></pre></td></tr></table></div></figure>


<p>对应的图片显示
<img src="http://blog.1nongfu.com/16850290270582.jpg" alt="" /></p>

<h4>5、总结</h4>

<p>这是一个很简单的分类网络，数据集也很简单，网络的架构有点像LeNet-5网络，不过99.16%的结果只能算一般般，还有优化的空间，目前网上准确率最高的有99.79%,所以还有提供的空间。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[安装frp内网穿透工具]]></title>
    <link href="http://xuyao.club/blog/2023/03/10/how-to-install-frp-vpn/"/>
    <updated>2023-03-10T10:30:17+08:00</updated>
    <id>http://xuyao.club/blog/2023/03/10/how-to-install-frp-vpn</id>
    <content type="html"><![CDATA[<h4>1、需求背景</h4>

<p>客户现场有几台服务器，是局域网的，因为要经常维护，显示每次去跑现场肯定是不合适的，为了便于维护和管理，可以装一个内网穿透工具&ndash;frp</p>

<!--more-->


<h4>2、安装</h4>

<ol>
<li>由于frp是golang语言写的，所以只要下载编译好的源码，直接跑就行，下载源码</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>下载最新版本的frp
</span><span class='line'>wget https://github.com/fatedier/frp/releases/download/v0.45.0/frp_0.45.0_linux_amd64.tar.gz</span></code></pre></td></tr></table></div></figure>


<p>解压gz包</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>tar -zxvf  frp_0.45.0_linux_amd64.tar.gz</span></code></pre></td></tr></table></div></figure>


<ol>
<li>配置frp，frp需要有一个公网ip，通过公网ip转发到要访问的局域网上，所以整个过程分为服务端和客户端，服务端是指有公网ip的那个服务器，客户端是需要访问的那台局域网<br/>
服务端的配置文件</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>打开配置文件
</span><span class='line'>vim frps.ini
</span><span class='line'>
</span><span class='line'>[common]
</span><span class='line'>bind_port = 8700 #配置需要转发的端口</span></code></pre></td></tr></table></div></figure>


<p>客户端配置文件</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>vim frpc.ini
</span><span class='line'>[common]
</span><span class='line'>server_addr = 106.14.xxx.161 #公网服务器的IP
</span><span class='line'>server_port = 8700 #公网服务端配置的端口
</span><span class='line'>
</span><span class='line'>[ssh]
</span><span class='line'>type = tcp
</span><span class='line'>local_ip = 127.0.0.1
</span><span class='line'>local_port = 22
</span><span class='line'>remote_port = 8600 #公网服务器的登录端口，</span></code></pre></td></tr></table></div></figure>


<ol>
<li>启动服务端和客户端
服务端启动</li>
</ol>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>./frps -c frps.ini</span></code></pre></td></tr></table></div></figure>


<p>客户端启动</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>./frpc -c frpc.ini</span></code></pre></td></tr></table></div></figure>


<p>这样整个过种就可以了,可以试下</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>通过端口登录公网的ip,实际是登录了局域网
</span><span class='line'>ssh -oPort=8600 root@106.14.xxx.161</span></code></pre></td></tr></table></div></figure>


<p>4.使用systemd启动frp,正常工作中，一般frp都要一直开着的，包括开机启动等，所以可以使用systemd来守护进程，
安装systemd</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># yum
</span><span class='line'>yum install systemd
</span><span class='line'># apt
</span><span class='line'>apt install systemd</span></code></pre></td></tr></table></div></figure>


<p>创建frps的配置文件</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>vim /etc/systemd/system/frps.service</span></code></pre></td></tr></table></div></figure>


<p>配置文件内容</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>[Unit]
</span><span class='line'># 服务名称，可自定义
</span><span class='line'>Description = frp server
</span><span class='line'>After = network.target syslog.target
</span><span class='line'>Wants = network.target
</span><span class='line'>
</span><span class='line'>[Service]
</span><span class='line'>Type = simple
</span><span class='line'># 启动frps的命令，需修改为您的frps的安装路径
</span><span class='line'>ExecStart = /path/to/frps -c /path/to/frps.ini 
</span><span class='line'># ExecStart = /path/to/frpc -c /path/to/frpc.ini
</span><span class='line'>
</span><span class='line'>[Install]
</span><span class='line'>WantedBy = multi-user.target</span></code></pre></td></tr></table></div></figure>


<p>使用systemd 命令，管理 frps。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># 启动frp
</span><span class='line'>systemctl start frps
</span><span class='line'># 停止frp
</span><span class='line'>systemctl stop frps
</span><span class='line'># 重启frp
</span><span class='line'>systemctl restart frps
</span><span class='line'># 查看frp状态
</span><span class='line'>systemctl status frps</span></code></pre></td></tr></table></div></figure>


<p>配置开机自动启动frps</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>systemctl enable frps</span></code></pre></td></tr></table></div></figure>


<p>查看frps启动日志</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>journalctl -u frps.service</span></code></pre></td></tr></table></div></figure>


<h4>3、身份认证</h4>

<p>frp还可以支持身份验证，有三种模式，token 和 oidc，默认为 token。<br/>
简单给个token身份验证的方式，这个也是最常用的。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># frps.ini 服务端
</span><span class='line'>[common]
</span><span class='line'>bind_port = 8700
</span><span class='line'>authentication_method = token
</span><span class='line'>token = QqQ27WRVKGUNxxxx
</span><span class='line'>
</span><span class='line'>
</span><span class='line'># frpc.ini 客户端
</span><span class='line'>[common]
</span><span class='line'>server_addr = 106.xx.xx.xx
</span><span class='line'>server_port = 8700
</span><span class='line'>authentication_method = token
</span><span class='line'>token = QqQ27WRVKGUNxxxx</span></code></pre></td></tr></table></div></figure>


<h4>4、配置自定义域名访问内网的Web服务</h4>

<p>可以使用vhost_http_port用来监听8080端口</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#frps.ini 服务端
</span><span class='line'>[common]
</span><span class='line'>bind_port = 7000
</span><span class='line'>vhost_http_port = 8800
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>#frpc.ini 客户端
</span><span class='line'>[web]
</span><span class='line'>type = http
</span><span class='line'>local_port = 8800
</span><span class='line'>custom_domains = xxx.1nongfu.com</span></code></pre></td></tr></table></div></figure>


<p>这样就可以通过浏览器访问<a href="http://xxx.1nongfu.com:8800">http://xxx.1nongfu.com:8800</a> 即可访问到处于内网机器上 8800 端口的服务，如果是静态资源可能还需要用nginx做个代理。</p>

<p>frp还有很多功能，这个是最简单的例子</p>

<h4>参考资料</h4>

<ol>
<li><a href="https://gofrp.org/docs/overview/">https://gofrp.org/docs/overview/</a></li>
<li><a href="https://gofrp.org/docs/setup/systemd/">https://gofrp.org/docs/setup/systemd/</a></li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Golang项目中的版本管理]]></title>
    <link href="http://xuyao.club/blog/2022/04/18/the-version-of-gloang-project/"/>
    <updated>2022-04-18T16:59:05+08:00</updated>
    <id>http://xuyao.club/blog/2022/04/18/the-version-of-gloang-project</id>
    <content type="html"><![CDATA[<p>go项目中经常会碰到线上编译好的二进制文件不清楚是哪次commit后编译的，每次编译出来的都是一个二进制文件，不利于管理，搞了个go项目的版本管理。
利用go build的 -ldflags 参数，使用帮助命令查看详细信息</p>

<!-- more -->


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>go build --ldflags="--help"</span></code></pre></td></tr></table></div></figure>


<p>参数很多，但我们感兴趣的是 -X</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>usage: link [options] main.o
</span><span class='line'>  -X definition
</span><span class='line'>      add string value definition of the form importpath.name=value</span></code></pre></td></tr></table></div></figure>


<p>-X 参数，指定 importpath.name=value，用于修改变量值。其中 importpath 表示包导入路径，name 是程序中的变量名，value 代表我们想要设定的变量值。
看一下最简单的例子</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>package main
</span><span class='line'>
</span><span class='line'>import (
</span><span class='line'> "fmt"
</span><span class='line'>)
</span><span class='line'>
</span><span class='line'>var (
</span><span class='line'> version = "0.0.0"
</span><span class='line'>)
</span><span class='line'>
</span><span class='line'>func main() {
</span><span class='line'> fmt.Println("version: ", version)
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<p>如果正常编译执行程序，将得到以下结果</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>go build -o main && ./main
</span><span class='line'>version:  0.0.0</span></code></pre></td></tr></table></div></figure>


<p>此时，我们指定 &ndash;ldflags  的 -X 参数重新编译执行</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>go build -o main --ldflags="-X 'main.version=1.0.0'" && ./main
</span><span class='line'>version:  1.0.0</span></code></pre></td></tr></table></div></figure>


<h5>项目中使用</h5>

<p>但是在实际项目中使用，肯定不会这么简单，需要一些更详细的信息，比如版本号，最后一次commit id，当前的branch,编译时间，编译环境等，
集成了一个包，以后可以在项目中直接用，github地址 <a href="https://github.com/xuyao91/version">version</a>
原理跟上面写的一样，作用&ndash;ldflags=&ldquo;-X"写实现变量值设定，example下面有个shell脚本，执行./build.sh脚本，会直接build项目并设定版本信息，最后运行</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>./example -version</span></code></pre></td></tr></table></div></figure>


<p>输出结果</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>Version: v1.0
</span><span class='line'>Go Version: go version go1.15.6 darwin/amd64
</span><span class='line'>Git Commit: 40a0e5935dcf1286c0c4e4b787167b04211e0324
</span><span class='line'>Git Branch: master
</span><span class='line'>Build Time: 2022-04-12 13:04:47</span></code></pre></td></tr></table></div></figure>


<p>这样就很方便管理编译后的二进制包了。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[2020年最后的一个小惊喜]]></title>
    <link href="http://xuyao.club/blog/2020/12/31/one-last-little-surprise-for-2020/"/>
    <updated>2020-12-31T09:55:41+08:00</updated>
    <id>http://xuyao.club/blog/2020/12/31/one-last-little-surprise-for-2020</id>
    <content type="html"><![CDATA[<p>想不到在2020年最后的几天，还有一个小惊喜。<br/>
我竟然通过了Certified Hyperledger Fabric Administrator (CHFA)的考试，这次考试没怎么备考，全程就只用了2-3周的时间复习了一下，本以后会过不了，没想到最后竟然考过了，还是很高兴的。</p>

<!-- more -->


<p><img src="http://blog.1nongfu.com/WechatIMG2040.png" alt="证书" /></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[非Docker环境部署Fabric]]></title>
    <link href="http://xuyao.club/blog/2020/08/26/deploy-fabric-to-a-non-docker-environment/"/>
    <updated>2020-08-26T11:09:59+08:00</updated>
    <id>http://xuyao.club/blog/2020/08/26/deploy-fabric-to-a-non-docker-environment</id>
    <content type="html"><![CDATA[<p>本文使用ubuntu 18作为系统，直接使用脚本启动Fabric网络，而非使用Docker容器来启动</p>

<h3>1、安装环境</h3>

<p><strong>1.1、安装Ubuntu系统</strong><br/>
到官网下载最新版的ubuntu镜像，我本地是使用虚拟机来安装ubuntu的，打开虚拟机，选择镜像文件，根据提示一路安装，</p>

<!-- more -->


<p><strong>1.2、安装Docker</strong><br/>
因为chaincode最终还是要在docker里跑，所以还是要先装一下docker环境<br/>
安装docker及docker-compose</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>apt install docker.io
</span><span class='line'>apt install docker-compose</span></code></pre></td></tr></table></div></figure>


<p>由于国内直接镜像比较慢，所以建议使用Docker镜像代理，在阿里云里使用”容器镜像服务->镜像加速器“，找到自己的镜像加速地址，根据不同的系统配置镜像加速器，ubuntu系统配置如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>sudo mkdir -p /etc/docker
</span><span class='line'>sudo tee /etc/docker/daemon.json &lt;&lt;-'EOF'
</span><span class='line'>{
</span><span class='line'>  "registry-mirrors": ["https://youkey.mirror.aliyuncs.com"]
</span><span class='line'>}
</span><span class='line'>EOF
</span><span class='line'>sudo systemctl daemon-reload
</span><span class='line'>sudo systemctl restart docker</span></code></pre></td></tr></table></div></figure>


<p>
<strong>1.3、安装Golang</strong><br/>
1、下载安装包到服务器上</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>wget https://dl.google.com/go/go1.14.1.linux-amd64.tar.gz</span></code></pre></td></tr></table></div></figure>


<p>2、解压安装包</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>tar -C /usr/local -xzf go1.14.1.linux-amd64.tar.gz</span></code></pre></td></tr></table></div></figure>


<p>3、设置环境变量</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>vim ~/.bash_profile
</span><span class='line'>
</span><span class='line'>export PATH=$PATH:/usr/local/go/bin
</span><span class='line'>export GOROOT=/usr/local/go
</span><span class='line'>export GOPATH=/data/works/go
</span><span class='line'>export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
</span><span class='line'>export GOBIN=$GOROOT/bin
</span><span class='line'>export GOPROXY=https://goproxy.io</span></code></pre></td></tr></table></div></figure>


<p><strong>1.4、安装其它工具</strong><br/>
安装一些系统操作的必要软件</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>apt install curl #curl工具
</span><span class='line'>apt-get install tree #树形结构查看文件
</span><span class='line'>apt-get install jq</span></code></pre></td></tr></table></div></figure>


<h3>2、Fabric安装和编译</h3>

<p><strong>2.1、下载源码</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>mkdir -p $GOPATH/src/github.com/hyperledger
</span><span class='line'>cd $GOPATH/src/github.com/hyperledger
</span><span class='line'>git clone https://github.com/hyperledger/fabric</span></code></pre></td></tr></table></div></figure>


<p><strong>2.2、安装相关依赖软件</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>go get github.com/golang/protobuf/protoc-gen-go
</span><span class='line'>mkdir -p $GOPATH/src/github.com/hyperledger/fabric/build/docker/gotools/bin
</span><span class='line'>cp  $GOPATH/bin/protoc-gen-go $GOPATH/src/github.com/hyperledger/fabric/build/docker/gotools/bin</span></code></pre></td></tr></table></div></figure>


<p><strong>2.3、编译Fabric模块</strong><br/>
进入到Fabirc源码所在的文件夹，执行以下命令可以一次完成Fabric 5个主要模块的编译过程，具体的命令如下所示：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>cd $GOPATH/src/github.com/hyperledger/fabric
</span><span class='line'>make release  #编译fabric模块
</span><span class='line'>make docker #做成镜像，如果需要</span></code></pre></td></tr></table></div></figure>


<p>对于Macos系统，在编译之前需要进行以下设置：</p>

<ul>
<li>打开文件$GOPATH/src/github.com/hyperledger/fabric/Makefile</li>
<li>找到其中的第一个GO_LDFLAGS字符串的位置，在该字符串所在行的在行的末尾加上字符串-s</li>
<li>保存文件Makefile
上述命令执行完成之后，会自动将将编译好的二进制文件存放在以下路径中：</li>
</ul>


<p>Ubuntu和Centos系统的存放路径</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$GOPATH/src/github.com/hyperledger/fabric/release/linux-amd64/bin</span></code></pre></td></tr></table></div></figure>


<p>Macos系统的存放路径</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$GOPATH/src/github.com/hyperledger/fabric/release/darwin-amd64/bin</span></code></pre></td></tr></table></div></figure>


<p><strong>2.4、Fabric模块安装</strong><br/>
编译完成之后，这些模块已经已经可以被运行了，但是目前只能在编译文件所在的文件夹中运行这些模块，这样是非常不方便的。为了更加方便的使用这些模块，可以通过下面的命令将这些模块的可执行文件复制到系统目录中，这样在系统中的任何路径下面都运行这些可执行这些模块。</p>

<p>Ubuntu和Centos将Fabric模块编译后的文件复制到系统文件夹中的方法如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>cp $GOPATH/src/github.com/hyperledger/fabric/release/linux-amd64/bin/* /usr/local/bin</span></code></pre></td></tr></table></div></figure>


<p>Macos上面将Fabric模块编译后的文件复制到系统文件夹中的方法如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>cp $GOPATH/src/github.com/hyperledger/fabric/release/darwin-amd64/bin/* /usr/local/bin</span></code></pre></td></tr></table></div></figure>


<p>复制成功之后通过以下命令修改文件的执行权限，否则无法执行。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>sudo chmod -R 775  /usr/local/bin/configtxgen
</span><span class='line'>sudo chmod -R 775  /usr/local/bin/configtxlator
</span><span class='line'>sudo chmod -R 775  /usr/local/bin/cryptogen
</span><span class='line'>sudo chmod -R 775  /usr/local/bin/peer
</span><span class='line'>sudo chmod -R 775  /usr/local/bin/orderer</span></code></pre></td></tr></table></div></figure>


<p>通过上面这些命令之后，可以在系统的任何路径下面运行这些模块了。下面通过一组命令来进检查安装过程是否成功。
<strong>2.5、检查各模块是否安装正确</strong><br/>
采用 version 命令行选项</p>

<table>
<thead>
<tr>
<th> 模块名称 </th>
<th> 功能 </th>
</tr>
</thead>
<tbody>
<tr>
<td> peer </td>
<td> 主节点模块，负责存储区块链数据，运行维护链码 </td>
</tr>
<tr>
<td> Orderer </td>
<td> 交易打包、排序模块 </td>
</tr>
<tr>
<td> cryptogen </td>
<td> 组织和证书生成模块 </td>
</tr>
<tr>
<td> configtxgen </td>
<td> 区块和交易生成模块 </td>
</tr>
<tr>
<td> configtxlator </td>
<td> 区块和交易解析模块 </td>
</tr>
</tbody>
</table>


<p><br/></p>

<h3>3、启动Fabric网络</h3>

<p><strong>3.1、生成Fabric需要的证书文件</strong><br/>
本例中我们将配置文件和生成的证书文件放在文件夹/opt/hyperledger/fabricconfig中。</p>

<p>创建存放证书的文件夹的命令如下所示：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>mkdir -p /opt/hyperledger/fabricconfig</span></code></pre></td></tr></table></div></figure>


<p>cryptogen提供了一个命令可以获取cryptogen模块所需要的配置文件的样式，该命令如下所示：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>cryptogen showtemplate</span></code></pre></td></tr></table></div></figure>


<p>可以把上述命令生成的内容复制到一个文件中稍加修改即可使用。本例中我们所使用的配置文件的内容如下所示：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>OrdererOrgs:
</span><span class='line'>  - Name: Orderer
</span><span class='line'>    Domain: xuyao.com
</span><span class='line'>    Specs:
</span><span class='line'>      - Hostname: orderer
</span><span class='line'>PeerOrgs:
</span><span class='line'>  - Name: Org1
</span><span class='line'>    Domain: org1.xuyao.com
</span><span class='line'>    Template:
</span><span class='line'>      Count: 2
</span><span class='line'>    Users:
</span><span class='line'>      Count: 3
</span><span class='line'>  - Name: Org2
</span><span class='line'>    Domain: org2.xuyao.com
</span><span class='line'>    Template:
</span><span class='line'>      Count: 2
</span><span class='line'>    Users:
</span><span class='line'>      Count: 2</span></code></pre></td></tr></table></div></figure>


<p>将上述文件的内容保存到文件夹/opt/hyperledger/fabricconfig中，配置文件夹命名为：crypto-config.yaml。保存之后执行如下命令：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>cd /opt/hyperledger/fabricconfig
</span><span class='line'>cryptogen generate --config=crypto-config.yaml --output ./crypto-config</span></code></pre></td></tr></table></div></figure>


<p>该命令执行完成之后我们会发现在文件夹/opt/hyperledger/fabricconfig中会新增加一个文件夹crypto-config，里面存放有本例的相关配置文件，可以通过tree命令查看生成证书文件的内容。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>cd /opt/hyperledger/fabricconfig
</span><span class='line'>tree -L 5</span></code></pre></td></tr></table></div></figure>


<p>执行命令 tree -L 5 显示如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>├── crypto-config
</span><span class='line'>│   ├── ordererOrganizations
</span><span class='line'>│   │   └── xuyao.com
</span><span class='line'>│   │       ├── ca
</span><span class='line'>│   │       ├── msp
</span><span class='line'>│   │       ├── orderers
</span><span class='line'>│   │       ├── tlsca
</span><span class='line'>│   │       └── users
</span><span class='line'>│   └── peerOrganizations
</span><span class='line'>│       ├── org1.xuyao.com
</span><span class='line'>│       │   ├── ca
</span><span class='line'>│       │   ├── msp
</span><span class='line'>│       │   ├── peers
</span><span class='line'>│       │   ├── tlsca
</span><span class='line'>│       │   └── users
</span><span class='line'>│       ├── org2.xuyao.com
</span><span class='line'>│       │   ├── ca
</span><span class='line'>│       │   ├── msp
</span><span class='line'>│       │   ├── peers
</span><span class='line'>│       │   ├── tlsca
</span><span class='line'>│       │   └── users</span></code></pre></td></tr></table></div></figure>


<p>在上述命令显示的内容中提取出后缀为 qklszzn.com域名。本例中提取信息如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>orderer.xuyao.com
</span><span class='line'>peer0.org1.xuyao.com
</span><span class='line'>peer1.org1.xuyao.com
</span><span class='line'>peer3.org1.xuyao.com
</span><span class='line'>peer0.org2.xuyao.com
</span><span class='line'>peer1.org2.xuyao.com</span></code></pre></td></tr></table></div></figure>


<p>通过上述步骤所有的证书文件都已经生成完毕，现在需要将测试域名映射到本机的IP地址上面，否则后面的操作可能会出现错误。
打开端映射文件,在打开的文件中设置如下内容</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>vi /etc/hosts</span></code></pre></td></tr></table></div></figure>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>192.168.23.212 orderer.xuyao.com
</span><span class='line'>192.168.23.212 peer0.org1.xuyao.com
</span><span class='line'>192.168.23.212 peer1.org1.xuyao.com
</span><span class='line'>192.168.23.212 peer3.org1.xuyao.com
</span><span class='line'>192.168.23.212 peer0.org2.xuyao.com
</span><span class='line'>192.168.23.212 peer1.org2.xuyao.com</span></code></pre></td></tr></table></div></figure>


<p><strong>3.2、生成创世块</strong><br/>
<strong>3.2.1、系统创始块的生成</strong><br/>
Fabric是基于区块链的分布式账本，每个账本都拥有自己的区块链，账本的区块链中会存储账本的交易，账本区块链中的第一个区块是个例外，该区块不存在交易数据而是存储配置信息，通常将账本的第一个区块成为创始块。综上所述，Fabric中账本的第一个区块是需要手动生成的。configtxgen模块是专门负责生成系统的创始块和Channel的创始块。configtxgen模块也需要一个配置文件来定义相关的属性。</p>

<p>在Fabric源码中提供的configtxgen模块所需要的配置文件的例子。该文件的路径是$GOPATH/src/github.com/hyperledger/fabric/sampleconfig，在这个目录下面有一个名为configtx.yaml的文件，对这个文件进行修即可使用。由于创始块文件是提供给Orderer节点使用，因此我们创建文件一个文件夹来存在Orderer节点相关的文件。文件夹创建之后把样例配置文件复制到该文件夹中。</p>

<p>创建存放configtxgen模块相关配置文件的文件夹的命令如下所示：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>mkdir -p /opt/hyperledger/order/
</span><span class='line'>cp -r $GOPATH/src/github.com/hyperledger/fabric/sampleconfig/configtx.yaml   /opt/hyperledger/order
</span><span class='line'>cd /opt/hyperledger/order</span></code></pre></td></tr></table></div></figure>


<p>对configtx.yaml进行修改，修改后的内容如下所示：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>
</span><span class='line'>Profiles:
</span><span class='line'>
</span><span class='line'>    TestTwoOrgsOrdererGenesis:
</span><span class='line'>        Orderer:
</span><span class='line'>            &lt;&lt;: *OrdererDefaults
</span><span class='line'>            Organizations:
</span><span class='line'>                - *OrdererOrg
</span><span class='line'>        Consortiums:
</span><span class='line'>            SampleConsortium:
</span><span class='line'>                Organizations:
</span><span class='line'>                    - *Org1
</span><span class='line'>                    - *Org2
</span><span class='line'>
</span><span class='line'>    TestTwoOrgsChannel:
</span><span class='line'>        Consortium: SampleConsortium
</span><span class='line'>        Application:
</span><span class='line'>            &lt;&lt;: *ApplicationDefaults
</span><span class='line'>            Organizations:
</span><span class='line'>                - *Org1
</span><span class='line'>                - *Org2
</span><span class='line'>
</span><span class='line'>Organizations:
</span><span class='line'>    - &OrdererOrg
</span><span class='line'>        Name: OrdererOrg
</span><span class='line'>        ID: OrdererMSP
</span><span class='line'>        MSPDir: /opt/hyperledger/fabricconfig/crypto-config/ordererOrganizations/xuyao.com/msp
</span><span class='line'>
</span><span class='line'>    - &Org1
</span><span class='line'>
</span><span class='line'>        Name: Org1MSP
</span><span class='line'>        ID: Org1MSP
</span><span class='line'>        MSPDir: /opt/hyperledger/fabricconfig/crypto-config/peerOrganizations/org1.xuyao.com/msp
</span><span class='line'>        AnchorPeers:
</span><span class='line'>            - Host: peer0.org1.xuyao.com
</span><span class='line'>              Port: 7051
</span><span class='line'>
</span><span class='line'>    - &Org2
</span><span class='line'>        Name: Org2MSP
</span><span class='line'>        ID: Org2MSP
</span><span class='line'>        MSPDir: /opt/hyperledger/fabricconfig/crypto-config/peerOrganizations/org2.xuyao.com/msp
</span><span class='line'>        AnchorPeers:
</span><span class='line'>            - Host: peer0.org2.xuyao.com
</span><span class='line'>              Port: 7051
</span><span class='line'>
</span><span class='line'>Orderer: &OrdererDefaults
</span><span class='line'>
</span><span class='line'>    OrdererType: solo
</span><span class='line'>    Addresses:
</span><span class='line'>        - orderer.xuyao.com:7050
</span><span class='line'>    BatchTimeout: 2s
</span><span class='line'>
</span><span class='line'>    BatchSize:
</span><span class='line'>        MaxMessageCount: 10
</span><span class='line'>        AbsoluteMaxBytes: 98 MB
</span><span class='line'>        PreferredMaxBytes: 512 KB
</span><span class='line'>
</span><span class='line'>    Kafka:
</span><span class='line'>        Brokers:
</span><span class='line'>            - 127.0.0.1:9092
</span><span class='line'>    Organizations:
</span><span class='line'>
</span><span class='line'>Application: &ApplicationDefaults
</span><span class='line'>
</span><span class='line'>    Organizations:</span></code></pre></td></tr></table></div></figure>


<p>配置文件修改完成之后执行如下面命令生成创始块文件。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>cd /opt/hyperledger/order
</span><span class='line'>configtxgen -profile  TestTwoOrgsOrdererGenesis  -outputBlock  ./genesis.block</span></code></pre></td></tr></table></div></figure>


<p>上述命令执行完成之后会在文件夹/opt/hyperledger/order中生成文件genesis.block。这是Fabric系统的创始块文件。<br/>
<br/>
<strong>3.2.2、账本创始块的生成</strong><br/>
创建Channel也是通过configtxgen模块完成的，创建Channel初始块的配置文件和创建系统初始块的配置文件是一样的，具体在本例中，Channel的创始块的配置信息已经定义在本节第一部分系统创始块的生成中生成的配置文件configtx.yaml中。</p>

<p>创建Channel的命令如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>configtxgen -profile  TestTwoOrgsChannel  -outputCreateChannelTx  ./roberttestchannel.tx -channelID  roberttestchannel</span></code></pre></td></tr></table></div></figure>


<p>上述命令执行完成之后会在目录生成文件roberttestchannel.tx，该文件用来生成Channel。除此之外还需要生成相关的锚点文件，生成锚点文件需要执行以下命令：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>configtxgen -profile  TestTwoOrgsChannel  -outputAnchorPeersUpdate ./Org1MSPanchors.tx -channelID  roberttestchannel -asOrg Org1MSP
</span><span class='line'>
</span><span class='line'>configtxgen -profile  TestTwoOrgsChannel  -outputAnchorPeersUpdate ./Org2MSPanchors.tx -channelID  roberttestchannel -asOrg Org2MSP</span></code></pre></td></tr></table></div></figure>


<p>上面命令执行完成之后会在相应的文件夹下面生成文件Org1MSPanchors.tx和Org2MSPanchors.tx，这些文件在后面会被使用到。</p>

<p><strong>3.3、Orderer节点的启动</strong><br/>
Orderer节点负责交易的打包和区块的生成。Orderer节点的配置信息通常放在环境变量或者配置文件中，本例中的配置信息统一存放在配置文件中。在Fabric源码提供了Orderer启动所用到的配置文件的实例，将示例配置文件复制到Orderer的文件夹下面修改即可使用。</p>

<p>复制配置文件到Orderer文件夹的命令如下所示：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>cd /opt/hyperledger/peer
</span><span class='line'>cp $GOPATH/src/github.com/hyperledger/fabric/sampleconfig/orderer.yaml /opt/hyperledger/orderer</span></code></pre></td></tr></table></div></figure>


<p>在模板配置文件上稍加修改即可满足本例使用，由于篇幅本例中我们只列出需要修改的部分。修改后配置文件中发生变化的内容如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>
</span><span class='line'>General:
</span><span class='line'>
</span><span class='line'>    LedgerType: file
</span><span class='line'>    ListenAddress: 0.0.0.0
</span><span class='line'>    ListenPort: 7050
</span><span class='line'>    TLS:
</span><span class='line'>        Enabled: false
</span><span class='line'>        PrivateKey: /opt/hyperledger/fabricconfig/crypto-config/ordererOrganizations/xuyao.com/orderers/orderer.xuyao.com/tls/server.key
</span><span class='line'>        Certificate: /opt/hyperledger/fabricconfig/crypto-config/ordererOrganizations/xuyao.com/orderers/orderer.xuyao.com/tls/server.crt
</span><span class='line'>        RootCAs:
</span><span class='line'>          - /opt/hyperledger/fabricconfig/crypto-config/ordererOrganizations/xuyao.com/orderers/orderer.xuyao.com/tls/ca.crt
</span><span class='line'>        ClientAuthEnabled: false
</span><span class='line'>        ClientRootCAs:
</span><span class='line'>    LogLevel: debug
</span><span class='line'>    LogFormat: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -&gt; %{level:.4s} %{id:03x}%{color:reset} %{message}'
</span><span class='line'>    GenesisMethod: file
</span><span class='line'>    GenesisProfile: TestOrgsOrdererGenesis
</span><span class='line'>    GenesisFile: /opt/hyperledger/order/orderer.genesis.block
</span><span class='line'>    LocalMSPDir: /opt/hyperledger/fabricconfig/crypto-config/ordererOrganizations/xuyao.com/orderers/orderer.xuyao.com/msp
</span><span class='line'>    LocalMSPID: OrdererMSP
</span><span class='line'>    Profile:
</span><span class='line'>        Enabled: false
</span><span class='line'>        Address: 0.0.0.0:6060
</span><span class='line'>    BCCSP:
</span><span class='line'>
</span><span class='line'>        Default: SW
</span><span class='line'>        SW:
</span><span class='line'>            Hash: SHA2
</span><span class='line'>            Security: 256
</span><span class='line'>            FileKeyStore:
</span><span class='line'>                KeyStore:
</span><span class='line'>FileLedger:
</span><span class='line'>    Location: /opt/hyperledger/order/production/orderer
</span><span class='line'>    Prefix: hyperledger-fabric-ordererledger
</span><span class='line'>RAMLedger:
</span><span class='line'>    HistorySize: 1000
</span><span class='line'>Debug:
</span><span class='line'>    BroadcastTraceDir:
</span><span class='line'>    DeliverTraceDir:</span></code></pre></td></tr></table></div></figure>


<p>在配置文件orderer.yaml所在的目录执行如下命令启动orderer</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>orderer start</span></code></pre></td></tr></table></div></figure>


<p><strong>3.4、Peer节点启动</strong><br/>
Peer模块是Fabric的核心节点，所有的交易数据经过Orderer排序打包之后由Peer模块存储在区块链中。所有的Chaincode也是有Peer模块打包并且激活的。Peer模块的配置信息同样由环境变量和配置文件组成，本例中我们采用配置文的方式来配置peer节点的参数。在设定配置文件之前需要创建一个文件夹存放Peer模块的配置文件和区块数据。在Fabric源码中同样提供了Peer模块配置文件的示例，将示例配置文件复制到Peer模块的文件夹下面修改即可使用。</p>

<p>创建存储Peer模块的配置文件和区块数据的文件夹，并复制示例配置文件的命令如下所示：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>mkdir -p /opt/hyperledger/peer
</span><span class='line'>cd /opt/hyperledger/peer
</span><span class='line'>cp  $GOPATH/src/github.com/hyperledger/fabric/sampleconfig/core.yaml /opt/hyperledger/peer</span></code></pre></td></tr></table></div></figure>


<p>在模板配置文件上稍加修改即可使用，由于篇幅本例中我们只列出需要修改的部分。修改后Peer模块配置文件中变化的内容如下所示：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
<span class='line-number'>120</span>
<span class='line-number'>121</span>
<span class='line-number'>122</span>
<span class='line-number'>123</span>
<span class='line-number'>124</span>
<span class='line-number'>125</span>
<span class='line-number'>126</span>
<span class='line-number'>127</span>
<span class='line-number'>128</span>
<span class='line-number'>129</span>
<span class='line-number'>130</span>
<span class='line-number'>131</span>
<span class='line-number'>132</span>
<span class='line-number'>133</span>
<span class='line-number'>134</span>
<span class='line-number'>135</span>
<span class='line-number'>136</span>
<span class='line-number'>137</span>
<span class='line-number'>138</span>
<span class='line-number'>139</span>
<span class='line-number'>140</span>
<span class='line-number'>141</span>
<span class='line-number'>142</span>
<span class='line-number'>143</span>
<span class='line-number'>144</span>
<span class='line-number'>145</span>
<span class='line-number'>146</span>
<span class='line-number'>147</span>
<span class='line-number'>148</span>
<span class='line-number'>149</span>
<span class='line-number'>150</span>
<span class='line-number'>151</span>
<span class='line-number'>152</span>
<span class='line-number'>153</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>logging:
</span><span class='line'>    peer:       debug
</span><span class='line'>    cauthdsl:   warning
</span><span class='line'>    gossip:     warning
</span><span class='line'>    ledger:     info
</span><span class='line'>    msp:        warning
</span><span class='line'>    policies:   warning
</span><span class='line'>    grpc:       error
</span><span class='line'>    format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -&gt; %{level:.4s} %{id:03x}%{color:reset} %{message}'
</span><span class='line'>peer:
</span><span class='line'>
</span><span class='line'>    id: peer0.org1.qklszzn.com
</span><span class='line'>    networkId: dev
</span><span class='line'>    listenAddress: 0.0.0.0:7051
</span><span class='line'>    chaincodeListenAddress: 0.0.0.0:7052
</span><span class='line'>    address: peer0.org1.xuyao.com:7051
</span><span class='line'>    addressAutoDetect: false
</span><span class='line'>    gomaxprocs: -1
</span><span class='line'>    gossip:
</span><span class='line'>
</span><span class='line'>        bootstrap: 127.0.0.1:7051
</span><span class='line'>        useLeaderElection: true
</span><span class='line'>        orgLeader: false
</span><span class='line'>        endpoint:
</span><span class='line'>        maxBlockCountToStore: 100
</span><span class='line'>        maxPropagationBurstLatency: 10ms
</span><span class='line'>        maxPropagationBurstSize: 10
</span><span class='line'>        propagateIterations: 1
</span><span class='line'>        propagatePeerNum: 3
</span><span class='line'>        pullInterval: 4s
</span><span class='line'>        pullPeerNum: 3
</span><span class='line'>        requestStateInfoInterval: 4s
</span><span class='line'>        publishStateInfoInterval: 4s
</span><span class='line'>        stateInfoRetentionInterval:
</span><span class='line'>        publishCertPeriod: 10s
</span><span class='line'>        skipBlockVerification: false
</span><span class='line'>        dialTimeout: 3s
</span><span class='line'>        connTimeout: 2s
</span><span class='line'>        recvBuffSize: 20
</span><span class='line'>        sendBuffSize: 200
</span><span class='line'>        digestWaitTime: 1s
</span><span class='line'>        requestWaitTime: 1s
</span><span class='line'>        responseWaitTime: 2s
</span><span class='line'>        aliveTimeInterval: 5s
</span><span class='line'>        aliveExpirationTimeout: 25s
</span><span class='line'>        reconnectInterval: 2
</span><span class='line'>        externalEndpoint: peer0.org1.qklszzn.com:7051
</span><span class='line'>        election:
</span><span class='line'>            startupGracePeriod: 15s
</span><span class='line'>            membershipSampleInterval: 1s
</span><span class='line'>            leaderAliveThreshold: 10s
</span><span class='line'>            leaderElectionDuration: 5s
</span><span class='line'>        pvtData:
</span><span class='line'>            maxPeers: 3
</span><span class='line'>            minAck:   3
</span><span class='line'>    events:
</span><span class='line'>        address: 0.0.0.0:7053
</span><span class='line'>        buffersize: 100
</span><span class='line'>        timeout: 10ms
</span><span class='line'>    tls:
</span><span class='line'>        enabled: false
</span><span class='line'>        cert:
</span><span class='line'>            file: /opt/hyperledger/fabricconfig/crypto-config/peerOrganizations/org1.xuyao.com/peers/peer0.org1.xuyao.com/tls/server.crt
</span><span class='line'>        key:
</span><span class='line'>            file: /opt/hyperledger/fabricconfig/crypto-config/peerOrganizations/org1.xuyao.com/peers/peer0.org1.xuyao.com/tls/server.key
</span><span class='line'>        rootcert:
</span><span class='line'>            file: /opt/hyperledger/fabricconfig/crypto-config/peerOrganizations/org1.xuyao.com/peers/peer0.org1.xuyao.com/tls/ca.crt
</span><span class='line'>        serverhostoverride:
</span><span class='line'>    fileSystemPath: /opt/hyperledger/peer/production
</span><span class='line'>    BCCSP:
</span><span class='line'>        Default: SW
</span><span class='line'>        SW:
</span><span class='line'>            Hash: SHA2
</span><span class='line'>            Security: 256
</span><span class='line'>            FileKeyStore:
</span><span class='line'>                KeyStore:
</span><span class='line'>
</span><span class='line'>    mspConfigPath: /opt/hyperledger/fabricconfig/crypto-config/peerOrganizations/org1.xuyao.com/peers/peer0.org1.xuyao.com/msp
</span><span class='line'>
</span><span class='line'>    localMspId: Org1MSP
</span><span class='line'>    profile:
</span><span class='line'>        enabled:     false
</span><span class='line'>        listenAddress: 0.0.0.0:6060
</span><span class='line'>    handlers:
</span><span class='line'>        authFilter: "DefaultAuth"
</span><span class='line'>        decorator: "DefaultDecorator
</span><span class='line'>vm:
</span><span class='line'>    endpoint: unix:///var/run/docker.soc
</span><span class='line'>    docker:
</span><span class='line'>        tls:
</span><span class='line'>            enabled: false
</span><span class='line'>            ca:
</span><span class='line'>                file: docker/ca.crt
</span><span class='line'>            cert:
</span><span class='line'>                file: docker/tls.crt
</span><span class='line'>            key:
</span><span class='line'>                file: docker/tls.key
</span><span class='line'>
</span><span class='line'>        attachStdout: false
</span><span class='line'>        hostConfig:
</span><span class='line'>            NetworkMode: host
</span><span class='line'>            Dns:
</span><span class='line'>            LogConfig:
</span><span class='line'>                Type: json-file
</span><span class='line'>                Config:
</span><span class='line'>                    max-size: "50m"
</span><span class='line'>                    max-file: "5"
</span><span class='line'>            Memory: 2147483648
</span><span class='line'>chaincode:
</span><span class='line'>    peerAddress:
</span><span class='line'>    id:
</span><span class='line'>        path:
</span><span class='line'>        name:
</span><span class='line'>    builder: $(DOCKER_NS)/fabric-ccenv:$(ARCH)-$(PROJECT_VERSION)
</span><span class='line'>    golang:
</span><span class='line'>        runtime: $(BASE_DOCKER_NS)/fabric-baseos:$(ARCH)-$(BASE_VERSION)
</span><span class='line'>    car:
</span><span class='line'>        runtime: $(BASE_DOCKER_NS)/fabric-baseos:$(ARCH)-$(BASE_VERSION)
</span><span class='line'>    java:
</span><span class='line'>        Dockerfile:  |
</span><span class='line'>            from $(DOCKER_NS)/fabric-javaenv:$(ARCH)-$(PROJECT_VERSION)
</span><span class='line'>    node:
</span><span class='line'>        runtime: $(BASE_DOCKER_NS)/fabric-baseimage:$(ARCH)-$(BASE_VERSION)
</span><span class='line'>    startuptimeout: 300s
</span><span class='line'>    executetimeout: 30s
</span><span class='line'>    mode: dev
</span><span class='line'>    keepalive: 0
</span><span class='line'>    system:
</span><span class='line'>        cscc: enable
</span><span class='line'>        lscc: enable
</span><span class='line'>        escc: enable
</span><span class='line'>        vscc: enable
</span><span class='line'>        qscc: enable
</span><span class='line'>        rscc: disable
</span><span class='line'>    logging:
</span><span class='line'>      level:  info
</span><span class='line'>      shim:   warning
</span><span class='line'>      format: '%{color}%{time:2006-01-02 15:04:05.000 MST} [%{module}] %{shortfunc} -&gt; %{level:.4s} %{id:03x}%{color:reset} %{message}'
</span><span class='line'>ledger:
</span><span class='line'>
</span><span class='line'>  blockchain:
</span><span class='line'>  state:
</span><span class='line'>    stateDatabase: goleveldb
</span><span class='line'>    couchDBConfig:
</span><span class='line'>       couchDBAddress: 127.0.0.1:5984
</span><span class='line'>       username:
</span><span class='line'>       password:
</span><span class='line'>       maxRetries: 3
</span><span class='line'>       maxRetriesOnStartup: 10
</span><span class='line'>       requestTimeout: 35s
</span><span class='line'>       queryLimit: 10000
</span><span class='line'>  history:
</span><span class='line'>    enableHistoryDatabase: true</span></code></pre></td></tr></table></div></figure>


<p>在配置文件core.yaml所在的文件夹中执行以下命令启动order节点</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>export set FABRIC_CFG_PATH=/opt/hyperledger/peer
</span><span class='line'>peer node start 
</span><span class='line'>#或者后台启动
</span><span class='line'>peer node start &gt;&gt; log_peer.log 2&gt;&1 &</span></code></pre></td></tr></table></div></figure>


<p><strong>3.5、创建通道</strong><br/>
现在我们可以创建通道，创建通道的过程一共需要三个步骤。</p>

<p>第一步： 创建通道</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>export set CORE_PEER_LOCALMSPID=Org1MSP
</span><span class='line'>export set CORE_PEER_MSPCONFIGPATH=/opt/hyperledger/fabricconfig/crypto-config/peerOrganizations/org1.qklszzn.com/users/Admin@org1.xuyao.com/msp
</span><span class='line'>
</span><span class='line'>cd /opt/hyperledger/order
</span><span class='line'>
</span><span class='line'>peer channel create -t 50s -o orderer.xuyao.com:7050 -c mychannel -f /opt/hyperledger/order/mychannel.tx</span></code></pre></td></tr></table></div></figure>


<p>创建通道完成之后，会在执行命令的当前目录生成名为mychannel.block的通道创始块文件</p>

<p>第二步：让已经运行的Peer模块加入通道</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>export set CORE_PEER_LOCALMSPID=Org1MSP
</span><span class='line'>export set CORE_PEER_ADDRESS=peer0.org1.xuyao.com:7051
</span><span class='line'>export set CORE_PEER_MSPCONFIGPATH=/opt/hyperledger/fabricconfig/crypto-config/peerOrganizations/org1.xuyao.com/users/Admin@org1.xuyao.com/msp
</span><span class='line'>
</span><span class='line'>peer channel join -b /opt/hyperledger/orderer/mychannel.block</span></code></pre></td></tr></table></div></figure>


<p>在上述创建通道的命令中-b后面的参数为第一步中生成的文件roberttestchannel.block，需要注意这个文件的路径。</p>

<p>第三步：更新锚节点</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>export set CORE_PEER_LOCALMSPID=Org1MSP
</span><span class='line'>export set CORE_PEER_ADDRESS=peer0.org1.xuyao.com:7051
</span><span class='line'>export set CORE_PEER_MSPCONFIGPATH=/opt/hyperledger/fabricconfig/crypto-config/peerOrganizations/org1.xuyao.com/users/Admin@org1.xuyao.com/msp
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>peer channel update -o orderer.xuyao.com:7050 -c mychannel -f  /opt/hyperledger/order/Org1MSPanchors.tx</span></code></pre></td></tr></table></div></figure>


<p><strong>3.6、Chaincode的部署和调用</strong><br/>
现在可以部署一个Chaincode（关于Chaincode的详细内容在本书的第七章会有详细的介绍）来测试Peer节点和Orderer节点的部署是否正确。这里采用Fabric源码自带的例子来作为测试Chaincode。测试用Chaincode的源代码路径如下所示</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$GOPATH/src/github.com/hyperledger/fabric/examples/chaincode/go/example02/cmd</span></code></pre></td></tr></table></div></figure>


<p>Chaincode相关的测试一共有四个步骤。
第一步： 部署chaincode代码</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>export set CORE_PEER_LOCALMSPID=Org1MSP
</span><span class='line'>export set CORE_PEER_ADDRESS=peer0.org1.xuyao.com:7051
</span><span class='line'>export set CORE_PEER_MSPCONFIGPATH=/opt/hyperledger/fabricconfig/crypto-config/peerOrganizations/org1.xuyao.com/users/Admin@org1.xuyao.com/msp
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>peer chaincode install -n xuyao_test_cc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/example02/cmd</span></code></pre></td></tr></table></div></figure>


<p>第二步： 实例化chaincode代码</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>export set CORE_PEER_LOCALMSPID=Org1MSP
</span><span class='line'>export set CORE_PEER_ADDRESS=peer0.org1.xuyao.com:7051
</span><span class='line'>export set CORE_PEER_MSPCONFIGPATH=/opt/hyperledger/fabricconfig/crypto-config/peerOrganizations/org1.xuyao.com/users/Admin@org1.xuyao.com/msp
</span><span class='line'>
</span><span class='line'>peer chaincode instantiate -o  orderer.xuyao.com:7050 -C mychannel -n xuyao_test_cc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR  ('Org1MSP.member','Org2MSP.member')"</span></code></pre></td></tr></table></div></figure>


<p>第三步：通过chaincode写入数据</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>export set CORE_PEER_LOCALMSPID=Org1MSP
</span><span class='line'>export set CORE_PEER_ADDRESS=peer0.org1.xuyao.com:7051
</span><span class='line'>export set CORE_PEER_MSPCONFIGPATH=/opt/hyperledger/fabricconfig/crypto-config/peerOrganizations/org1.xuyao.com/users/Admin@org1.xuyao.com/msp
</span><span class='line'>
</span><span class='line'>peer chaincode invoke -o orderer.xuyao.com:7050 -C mychannel -n xuyao_test_cc -c '{"Args":["invoke","a","b","1"]}'</span></code></pre></td></tr></table></div></figure>


<p>第四步：通过chaincode查询数据</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>export set CORE_PEER_LOCALMSPID=Org1MSP
</span><span class='line'>export set CORE_PEER_ADDRESS=peer0.org1.xuyao.com:7051
</span><span class='line'>export set CORE_PEER_MSPCONFIGPATH=/opt/hyperledger/fabricconfig/crypto-config/peerOrganizations/org1.xuyao.com/users/Admin@org1.xuyao.com/msp
</span><span class='line'>
</span><span class='line'>peer chaincode query -C mychannel -n xuyao_test_cc -c '{"Args":["query","a"]}'</span></code></pre></td></tr></table></div></figure>


<p>如果上述命令都能正确执行，那么一个简单的Fabric系统就已经部署完成了。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[密码学(三)之对称加密与非对称加密]]></title>
    <link href="http://xuyao.club/blog/2019/09/09/symmetric-encryption-and-asymmetric-encryption/"/>
    <updated>2019-09-09T14:26:46+08:00</updated>
    <id>http://xuyao.club/blog/2019/09/09/symmetric-encryption-and-asymmetric-encryption</id>
    <content type="html"><![CDATA[<p>&emsp;这是之前在公司内部做技术分享的文档，主要是讲解了对称加密和非对称加密的基本原理以及一些例子，现将它上传到blog上，做个备份。
PDF文件下载地址-> <a href="http://img.1nongfu.com/%E5%AF%B9%E7%A7%B0%E5%8A%A0%E5%AF%86%E4%B8%8E%E9%9D%9E%E5%AF%B9%E7%A7%B0%E5%8A%A0%E5%AF%86.pdf">对称加密与非对称加密</a></p>

<!-- more -->


<p><img src="http://img.1nongfu.com/image-20190909143504582.png" alt="image-20190909143504582" />
<img src="http://img.1nongfu.com/image-20190909143520880.png" alt="image-20190909143520880" />
<img src="http://img.1nongfu.com/image-20190909143545320.png" alt="image-20190909143545320" />
<img src="http://img.1nongfu.com/image-20190909144913397.png" alt="image-20190909144913397" />
<img src="http://img.1nongfu.com/image-20190909144930588.png" alt="image-20190909144930588" />
<img src="http://img.1nongfu.com/image-20190909144948085.png" alt="image-20190909144948085" />
<img src="http://img.1nongfu.com/image-20190909145000065.png" alt="image-20190909145000065" />
<img src="http://img.1nongfu.com/image-20190909145016128.png" alt="image-20190909145016128" />
<img src="http://img.1nongfu.com/image-20190909145038512.png" alt="image-20190909145038512" />
<img src="http://img.1nongfu.com/image-20190909145715696.png" alt="image-20190909145715696" />
<img src="http://img.1nongfu.com/image-20190909145054241.png" alt="image-20190909145054241" />
<img src="http://img.1nongfu.com/image-20190909145741242.png" alt="image-20190909145741242" />
<img src="http://img.1nongfu.com/image-20190909145125180.png" alt="image-20190909145125180" />
<img src="http://img.1nongfu.com/image-20190909145807527.png" alt="image-20190909145807527" />
<img src="http://img.1nongfu.com/image-20190909145823090.png" alt="image-20190909145823090" />
<img src="http://img.1nongfu.com/image-20190909145837767.png" alt="image-20190909145837767" />
<img src="http://img.1nongfu.com/image-20190909145849776.png" alt="image-20190909145849776" />
<img src="http://img.1nongfu.com/image-20190909145926888.png" alt="image-20190909145926888" />
<img src="http://img.1nongfu.com/image-20190909145940375.png" alt="image-20190909145940375" />
<img src="http://img.1nongfu.com/image-20190909151644589.png" alt="image-20190909151644589" />
<img src="http://img.1nongfu.com/image-20190909150000693.png" alt="image-20190909150000693" />
<img src="http://img.1nongfu.com/image-20190909150024876.png" alt="image-20190909150024876" />
<img src="http://img.1nongfu.com/image-20190909150042448.png" alt="image-20190909150042448" /></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[腾讯云区块链服务平台介绍及接入]]></title>
    <link href="http://xuyao.club/blog/2019/06/21/the-tbaas-of-tencent/"/>
    <updated>2019-06-21T16:17:20+08:00</updated>
    <id>http://xuyao.club/blog/2019/06/21/the-tbaas-of-tencent</id>
    <content type="html"><![CDATA[<p><strong>1、TBaas简介</strong></p>

<p>&emsp;1.1、TBaas简介</p>

<p>&emsp;1.2、Hyperledger Fabric的架构</p>

<p>&emsp;1.3、TBaaS的架构</p>

<p><strong>2、如何使用TBaaS</strong></p>

<p>&emsp;2.1、创建联盟</p>

<p>&emsp;2.2、Channel管理</p>

<p>&emsp;2.3、ChainCode管理</p>

<!-- more -->


<p><strong>3、数据如何上链</strong></p>

<p>&emsp;3.1、编写ChainCode</p>

<p>&emsp;3.2、调用Fabric交易相关接口</p>

<p>&emsp;3.3、调用Fabric区块链浏览器相关接口</p>

<p><strong>4、需要注意的问题</strong></p>

<p>&emsp;4.1、哪些数据适合存储在链上？</p>

<p>&emsp;4.2、上链的性能问题</p>

<p>&emsp;4.3、上链的数据隐私问题</p>

<h3>1、TBaaS简介</h3>

<h4>1.1、TBaas简介</h4>

<p>腾讯云区块链服务平台（TBaaS）是一个企业级的区块链开放平台，可一键式快速部署接入、拥有去中心化信任机制、集合众多区块链底层技术的区块链服务平台，目前已支持 Hyperledger Fabric 与 FISCO-BCOS 区块链底层平台，后续将支持 Corda、EEA 等不同区块链底层技术。平台目前支持私有链与联盟链两种模式，</p>

<p>TBaaS有一个重要特性是<strong>多链支持</strong>，这是其它普通联盟链没有的，不过从他的白皮书的了解到，TBaaS所说的多链并不是真正物理上的多链，而是TBaaS平台将自己的成员系统+通道组成的一个<strong>具有用户权限的多Channel(通道)管理平台</strong>，即逻辑上的多链，以下是官方白皮书对多链的说明。</p>

<blockquote><p>一条逻辑上的区块链是集合了特定组织、特定节点的私有区块链系统，不同的组织间可以建立不同的逻辑区块链，链间实现数据隔离，智能合约可以部署在不同的逻辑区块链之上。</p>

<p>在TBaaS系统中，支持用户在同一个区块链系统中建立多个不同的逻辑区块链，即多链。多链
中每一条链都是包含记账节点、共识节点、智能合约和账簿的逻辑结构，它将参与者与数据(包含智
能合约)进行隔离，实现了不同角色的用户访问权限不同，数据进行安全控制的基本要求。</p></blockquote>

<p><a href="https://main.qcloudimg.com/raw/565be73decf6badd55779613908a3319/%E8%85%BE%E8%AE%AF%E4%BA%91%E5%8C%BA%E5%9D%97%E9%93%BETBaaS%E4%BA%A7%E5%93%81%E7%99%BD%E7%9A%AE%E4%B9%A6.pdf">点击查看白皮书全文</a></p>

<p><img src="http://blog.1nongfu.com/image-20190605172519389.png" alt="image-20190605172519389" /></p>

<h4>1.2、Hyperledger Fabric的架构</h4>

<p>在说TBaaS之前，简单介绍一下Fabric。</p>

<p>Hyperledger Fabric 是一个企业级的区块链框架实现，是 Linux 基金会旗下托管的 Hyperledger 开源项目之一，具有高度的模块化、可配置设计，拥有完备的成员管理和治理措施，支持可插拔的共识协议。</p>

<p>Hyperledger Fabric 不需要利用传统的发币、挖矿、PoW 工作量证明等手段来激励参与方。针对联盟链场景，差异化设计使得 Fabric 成为当前性能优秀、广受认可的区块链底层引擎。</p>

<p>下面是Fabric整个架构图，</p>

<p><img src="http://blog.1nongfu.com/image-20190606151636463.png" alt="image-20190606151636463" /></p>

<p>整个Fabric网络由成员管理服务、区块链服务、链码服务三大块组成，其中区块链服务就是整个架构中最重要、也是最难的部分，因为在整个部署过程中，docker服务很多，docker之前互相通信，只要其中一个服务启动有问题，就会影响整个联盟网络，所以操作起来非常复杂。</p>

<p>但在TBaaS中，Fabric作为TBaaS中底层引擎最重要的一种联盟链，区块链服务这块已由平台事先初始化好了，并且平台集成了腾讯云的用户系统，<strong>TBaaS平台将Fabric的成员管理和腾讯云的用户系统打通</strong>，这样在以后的成员管理，上链服务，多链上起到了很大的作用，同时作为企业，我们并不需要关心TBaaS底层的联盟链和用户管理的问题，我们只需要考虑ChainCode（智能合约）部分对接就可以。</p>

<p>如果一个项目需要将数据上传到Fabric联盟链中，整个Fabric项目基本会分为三大块，如下图</p>

<p><img src="http://blog.1nongfu.com/image-20190605181853438.png" alt="image-20190605181853438" /></p>

<p>Fabric联盟链、Fabric区块链浏览器、API接口服务，Fabric联盟链是整个区块链的核心，联盟链中有什么，可以参考上面Fabric框架图，企业将数据上链，首先要编写Chaincode，将智能合约安装到通道中，再通过API接口服务调用ChainCode，将数据上链，企业还需搭建区块链浏览器，用于查询上链的数据，所以传统的Fabric联盟链中，企业需要做三块内容：</p>

<ul>
<li>编写ChainCode</li>
<li>编写API接口服务</li>
<li>部署(编写)区块链浏览器</li>
</ul>


<h4>1.3、TBaaS的架构</h4>

<p>TBaaS依托腾讯金融云基础设施，集开发、管理、运维和数据存储等功能为一体的一站式区块链服务平台。基于 TBaaS 区块链服务平台，客户可以降低对区块链底层技术的获取成本，专注在区块链业务模式创新及业务应用的开发和运营之中。TBaaS 区块链服务平台集合众多区块链底层技术，目前已支持 Hyperledger Fabric 与 FISCO-BCOS 区块链底层平台，后续将支持 Corda、EEA 等不同区块链底层技术，下面是TBaaS的整体架构图</p>

<p><img src="http://blog.1nongfu.com/image-20190605211810925.png" alt="image-20190605211810925" /></p>

<p>可以看到TBaaS架构比Fabric架构丰富了很多，TBaaS从创建联盟、成员管理、证书管理、合约的管理及在线编辑等都做了可视化界面，这大大缩减了开发人员的时间和成本，TBaaS还集成了运维管理，从监控警告到策略配置都有一套可视化界面，所以TBaaS把整个区块链服务做成了一个标准服务，这样企业可以更专注在区块链业务模式创新及业务应用的开发和运营之中。</p>

<h3>2、如何使用TBaaS</h3>

<h4>2.1、创建联盟链</h4>

<p>这里简要说明一下如何创建及管理整个TBaaS联盟链的过程，首先需要使用账号、密码登录腾讯云平台，进入管理后台通过 云产品->TBaas 进入 腾讯的TBaas管理后台。</p>

<h5>2.1.1、创建联盟</h5>

<p>联盟对应一个区块链业务团体，一个区块链业务团体可以由一个或者多个腾讯云用户组成。联盟可由腾讯云用户免费创建，在新建联盟过程中，只需要填写联盟名称、联盟的描述即可。</p>

<p><img src="https://main.qcloudimg.com/raw/5934187a9764184a945eedc2ab2407b6.png" alt="img" /></p>

<h5>2.1.2、邀请成员</h5>

<p>联盟成员可以邀请其他成员加入联盟，在 “联盟列表” 或者 “联盟详情” 页面中，单击 “邀请成员” ，进行成员邀请。</p>

<p><img src="https://main.qcloudimg.com/raw/2e5b9ac6aef2a4a5742bf2ff1611521c.png" alt="img" /></p>

<h5>2.1.3、创建区块链网络</h5>

<p>创建联盟后，可以在该联盟下创建区块链网络及配置组织和节点</p>

<p><img src="http://blog.1nongfu.com/image-20190605214420286.png" alt="image-20190605214420286" /></p>

<p>点击创建网络来创建一个联盟链网络</p>

<p><img src="http://blog.1nongfu.com/image-20190605214757114.png" alt="image-20190605214757114" /></p>

<p><img src="http://blog.1nongfu.com/image-20190605215451472.png" alt="image-20190605215451472" /></p>

<p>一个成员只能创建一个组织且每个组织最大只支持10个节点，</p>

<h4>2.2、Channel管理</h4>

<p>2.1的步骤走完后，整个联盟链的底层基础网络已经全部创建好，接下来需要创建通道，并将通道加入到组织中</p>

<h5>2.2.1、创建Channel</h5>

<p>在通道管理中点击新建智能合约。</p>

<p><img src="http://blog.1nongfu.com/image-20190605215907421.png" alt="image-20190605215907421" /></p>

<h5>2.2.2、 将Channel加入节点</h5>

<p>在 “通道管理” 页签中，选择待加入节点的通道名称，单击【加入节点】。如下图所示：</p>

<p><img src="https://main.qcloudimg.com/raw/d4ce424bc8fffcad07b6b43673dcdfa5.png" alt="加入节点" /></p>

<h5>2.2.3、邀请组织</h5>

<p>一个联盟链中可以有多个通道，且每个通道可以邀请不同的组织加入该通道，</p>

<p>在 “通道管理” 页签中，选择待邀请组织的通道名称，单击【邀请组织】。如下图所示：</p>

<p><img src="http://blog.1nongfu.com/image-20190606151835949.png" alt="image-20190606151835949" /></p>

<h4>2.3、ChainCode(智能合约)管理</h4>

<p>智能合约开发是区块链应用的主要功能，所有区块链业务能力围绕智能合约为核心，来实
现智能合同、自动触发、安全隔离、业务定义、数字协议等功能，因此智能合约是区块链应用开发
过程中最主要的部分，下面整个智能合约的生命周期图：</p>

<h5><img src="http://blog.1nongfu.com/image-20190606114621404.png" alt="image-20190606114621404" />2.3.1、查看/新增合约</h5>

<p>进入合约管理的 “区块链网络”，进入 “区块链网络” 信息页面，选择"合约管理"，可以在线新建一个合约，要注意的是，合约是用Go语言写的，如下图</p>

<p><img src="http://blog.1nongfu.com/image-20190606151900620.png" alt="image-20190606151900620" /></p>

<p>单击【在线编辑】，可在区块链网络上编辑与使用智能合约。如下图所示：
具体操作可以按照使用指引使用智能合约 IDE 编辑器。</p>

<p><img src="http://blog.1nongfu.com/image-20190606151927206.png" alt="image-20190606151927206" /></p>

<h5>2.3.1 安装合约</h5>

<p>点击下图合约列表右边的安装，可以将编写好的合约安装到某个组织里</p>

<p><img src="http://blog.1nongfu.com/image-20190606151950163.png" alt="image-20190606151950163" /></p>

<h5>2.3.2、实例化合约</h5>

<p>安装好合约后，需要再实例化合约，点击<strong>实例化合约，系统会启动一个Docker服务来运行这个智能合约</strong>，如果在所有的组织里都安装、实例化智能合约，那会就会起相应数量的Docker服务来运行每个组织里的智能合约，注意<strong>一定要先安装合约，再实例化合约</strong>。</p>

<h5>2.3.3、升级合约</h5>

<p>有时候业务变动，需要修改合约内容，这时候修改后的合约内容要重新生效，就需要升级合约，同样如果在多个组织里都有对应的合约，则需要一个一个地升级。</p>

<h3>3、数据如何上链</h3>

<p>上面的步骤走完，整个TBaaS平台的区块链网络已经全部安装好，接下来就是要做企业如何对接TBaaS的联盟链，先来看下下面这张图，可以看到，TBaaS已经帮我们把整个网络都封装好了，我们只要调相关接口及编写智能合约就可以，整个项目对接只需要做如下三点即可：</p>

<ul>
<li>编写ChainCode</li>
<li>调用TBaaS平台提供的Fabric交易相关API</li>
<li>调用TBaas平台提供的Fabric区块链浏览器相关API</li>
</ul>


<p><img src="http://blog.1nongfu.com/image-20190606091920521.png" alt="image-20190606091920521" /></p>

<h4>3.1、编写ChainCode</h4>

<p>TBaaS平台提供了一套很完善的在线编写智能合约的服务，使用在线IDE，可以直接编写和编译</p>

<p><img src="http://blog.1nongfu.com/image-20190606151927206.png" alt="å¨çº¿ç¼è¾" /></p>

<p>需要注意的是，ChainCode官方文档显示可以使用Go,NodeJs,Java来编写合约，但是<strong>官方推荐使用Go语言来编写智能合约</strong>，合约具体内容根据我们业务来定，合约编写好后，具体的安装和实例化可以查看2.3的内容，</p>

<h4>3.2、调用Fabric交易相关接口</h4>

<p>合约编写好后，通过安装和实例化后，就可以调用这个合约来将数据上链，TBaaS官方提供了三个Fabric交易相关的接口，分别是：</p>

<ul>
<li>Invoke异步调用结果查询</li>
<li>新增交易</li>
<li>交易查询</li>
</ul>


<p>下面简要说下这三个接口的作用，详细文档可以查看<a href="https://cloud.tencent.com/document/product/663/19465">官方文档</a></p>

<h5>3.2.1、 Invoke异步调用结果查询</h5>

<p>本接口是查询上链数据是否有效、成功，注意是异步的，TBaaS平台也提供了在线调试工具，如下图</p>

<p><img src="http://blog.1nongfu.com/image-20190606104848714.png" alt="image-20190606104848714" /></p>

<p>注意<strong>调用Fabric相关的接口，官方提供了， Python、Java、NodeJs、PHP、GO语言的SDK，所以调用这些接口时，看我们自己技术方便，随便选用哪种语言的SDK都可以</strong></p>

<p>下面是是 Invoke异步调用结果查询的一个官方示例，可以看下</p>

<p><strong>输入示例</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>https://tbaas.tencentcloudapi.com/?Action=GetInvokeTx
</span><span class='line'>&Module=transaction
</span><span class='line'>&Operation=query_txid
</span><span class='line'>&ClusterId=251005746envnew
</span><span class='line'>&ChannelName=ch042103
</span><span class='line'>&PeerName=peer0.neworg02.envnew
</span><span class='line'>&PeerGroup=NewOrg02
</span><span class='line'>&TxId=280e9f1436c3ce045af4f3c7060ff217583585d41faf1f1daa99387419bac07c
</span><span class='line'>&GroupName=NewOrg02
</span><span class='line'>&&lt;公共请求参数&gt;</span></code></pre></td></tr></table></div></figure>


<p><strong>输出示例</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{
</span><span class='line'>  "Response": {
</span><span class='line'>    "BlockId": 6,
</span><span class='line'>    "RequestId": "551b801e-6dbe-46be-aa46-f8cc3ff1cd09",
</span><span class='line'>    "TxValidationCode": 0,
</span><span class='line'>    "TxValidationMsg": "VALID"
</span><span class='line'>  }
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<h5>3.2.2、新增交易</h5>

<p>这个接口应该是最重要的一个接口，就是将我们自己的数据上链，具体把什么数据上链，可以根据我们自己的业务系统来，数据上链成功后会返回一个Txid，这个交易ID是数据在链上的唯一标识，应该需要存储到我们的业务系统，以后可能用到这个Txid来查询链上的数据。</p>

<p>下面是一个示例：</p>

<p><strong>输入示例</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>https://tbaas.tencentcloudapi.com/?Action=Invoke
</span><span class='line'>&Module=transaction
</span><span class='line'>&Operation=invoke
</span><span class='line'>&ClusterId=251005746envnew
</span><span class='line'>&Peers.0.PeerName=peer0.neworg02.envnew
</span><span class='line'>&Peers.0.OrgName=NewOrg02
</span><span class='line'>&ChannelName=ch042103
</span><span class='line'>&ChaincodeName=cc050301
</span><span class='line'>&FuncName=createCar
</span><span class='line'>&Args.0=CAR92
</span><span class='line'>&Args.1=Chevy
</span><span class='line'>&Args.2=Volt
</span><span class='line'>&Args.3=Black
</span><span class='line'>&Args.4=Nick
</span><span class='line'>&GroupName=NewOrg02
</span><span class='line'>&&lt;公共请求参数&gt;</span></code></pre></td></tr></table></div></figure>


<p><strong>输出示例</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{
</span><span class='line'>  "Response": {
</span><span class='line'>    "Events": "myOrgpeer0.myorg.envnew:VALID",
</span><span class='line'>    "RequestId": "0b82b65e-7100-49f1-9f29-e934a8833711",
</span><span class='line'>    "Txid": "0366ab8f31c9f8aa6b9fc9506fa841e55d1ecd492b3ecc373c0f66ca49f33ea1"
</span><span class='line'>  }
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<h5>3.2.3、交易查询</h5>

<p>数据上链后，需要查看相关链上数据，注意这个查询接口是可以根据用户上链的数据查询，而不是根据上面的接口的Txid来查询，也就是说这个接口的查询交易的参数用户是可以自己自定义的，下面看下示例。</p>

<p><strong>输入示例</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>https://tbaas.tencentcloudapi.com/?Action=Query
</span><span class='line'>&Module=transaction
</span><span class='line'>&Operation=query
</span><span class='line'>&ClusterId=251005746envnew
</span><span class='line'>&Peers.0.PeerName=peer0.neworg02.envnew
</span><span class='line'>&Peers.0.OrgName=NewOrg02
</span><span class='line'>&ChannelName=ch042103
</span><span class='line'>&ChaincodeName=cc050301
</span><span class='line'>&FuncName=queryCar
</span><span class='line'>&Args.0=CAR92
</span><span class='line'>&GroupName=NewOrg02
</span><span class='line'>&&lt;公共请求参数&gt;</span></code></pre></td></tr></table></div></figure>


<p><strong>输出示例</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{
</span><span class='line'>  "Response": {
</span><span class='line'>    "Data": [
</span><span class='line'>      "{\"make\":\"Chevy\",\"model\":\"Volt\",\"colour\":\"Black\",\"owner\":\"Nick\"}"
</span><span class='line'>    ],
</span><span class='line'>    "RequestId": "3f6836c5-e889-431e-b932-47a1653c5f7b"
</span><span class='line'>  }
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<p>可以看到Args.0=CAR92是自己定义的上链数据，并不是Txid。</p>

<h4>3.3、调用Fabric区块链浏览器相关接口</h4>

<p>TBaaS并没有直接提供给我们一个区块链浏览器相关的平台 ，只是提供了三个接口给我们，供我们自己查询，<strong>我们可以通过这些接口自己做一个简单的TBaaS版区块链浏览器出来，实现区块链数据的可视化管理</strong>，接口分别如下：</p>

<ul>
<li><p>查询区块列表</p></li>
<li><p>获取区块链网络概要</p></li>
<li><p>获取最新交易列表</p></li>
</ul>


<h5>3.3.1、查询区块列表</h5>

<p>这个接口可以查看链上所有的区块数据，分页展示，可以在我们自己的系统里把链上所有的数据都分页展示出来，可以看下示例：</p>

<p><strong>输入示例</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>https://tbaas.tencentcloudapi.com/?Action=GetBlockList
</span><span class='line'>&Module=block
</span><span class='line'>&Operation=block_list
</span><span class='line'>&ChannelId=0
</span><span class='line'>&GroupId=0
</span><span class='line'>&ChannelName=kylotst
</span><span class='line'>&GroupName=liulanOrg
</span><span class='line'>&ClusterId=251005746bc0f03q8u93j
</span><span class='line'>&Offset=0
</span><span class='line'>&Limit=10
</span><span class='line'>&&lt;公共请求参数&gt;</span></code></pre></td></tr></table></div></figure>


<p><strong>输出示例</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{
</span><span class='line'>  "Response": {
</span><span class='line'>    "BlockList": [
</span><span class='line'>      {
</span><span class='line'>        "BlockId": 5,
</span><span class='line'>        "BlockNum": 5,
</span><span class='line'>        "DataHash": "92f1c3b1eb0eb1bc1825f1acd3474e7679b2a97cdf8d6155ed6a0e6c1458e479",
</span><span class='line'>        "PreHash": "92f1c3b1eb0eb1bc1825f1acd3474e7679b2a97cdf8d6155ed6a0e6c1458e479",
</span><span class='line'>        "TxCount": 1
</span><span class='line'>      },
</span><span class='line'>      {
</span><span class='line'>        "BlockId": 4,
</span><span class='line'>        "BlockNum": 4,
</span><span class='line'>        "DataHash": "17e381e65605963c9211abc5b72d80cf3a6a4955ff7b61c70b406b98c90ded6f",
</span><span class='line'>        "PreHash": "17e381e65605963c9211abc5b72d80cf3a6a4955ff7b61c70b406b98c90ded6f",
</span><span class='line'>        "TxCount": 1
</span><span class='line'>      },
</span><span class='line'>      {
</span><span class='line'>        "BlockId": 3,
</span><span class='line'>        "BlockNum": 3,
</span><span class='line'>        "DataHash": "32b80e93141467eda367f05a2428a6c03369405ae10349db7fad0762e9b56cc2",
</span><span class='line'>        "PreHash": "32b80e93141467eda367f05a2428a6c03369405ae10349db7fad0762e9b56cc2",
</span><span class='line'>        "TxCount": 1
</span><span class='line'>      },
</span><span class='line'>      {
</span><span class='line'>        "BlockId": 2,
</span><span class='line'>        "BlockNum": 2,
</span><span class='line'>        "DataHash": "8be5094bf40c5b7e410cc3e8aa33354da2aa78db862e17cfd5fa783dddc1ee3a",
</span><span class='line'>        "PreHash": "8be5094bf40c5b7e410cc3e8aa33354da2aa78db862e17cfd5fa783dddc1ee3a",
</span><span class='line'>        "TxCount": 1
</span><span class='line'>      },
</span><span class='line'>      {
</span><span class='line'>        "BlockId": 1,
</span><span class='line'>        "BlockNum": 1,
</span><span class='line'>        "DataHash": "af319fe2ff9e5830af0f07200adf965156446a205137e61d87f1db0b8f43cc7e",
</span><span class='line'>        "PreHash": "af319fe2ff9e5830af0f07200adf965156446a205137e61d87f1db0b8f43cc7e",
</span><span class='line'>        "TxCount": 1
</span><span class='line'>      },
</span><span class='line'>      {
</span><span class='line'>        "BlockId": 0,
</span><span class='line'>        "BlockNum": 0,
</span><span class='line'>        "DataHash": "96f22d00947478c1b16c2aec5e7079c761b168d304cadf19a14a032ee8f64a23",
</span><span class='line'>        "PreHash": "96f22d00947478c1b16c2aec5e7079c761b168d304cadf19a14a032ee8f64a23",
</span><span class='line'>        "TxCount": 1
</span><span class='line'>      }
</span><span class='line'>    ],
</span><span class='line'>    "RequestId": "018328c8-9c24-4104-a0ad-a7a31c033278",
</span><span class='line'>    "TotalCount": 6
</span><span class='line'>  }
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<h5>3.3.2、获取区块链网络概要</h5>

<p>这个接口可以查看区块网络的一个概要信息，包括当前通道数量、组织数量、节点数量、合约数量、Orderer数量等，下面是一个示例：</p>

<p><strong>输入示例</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>https://tbaas.tencentcloudapi.com/?Action=GetClusterSummary
</span><span class='line'>&Module=cluster_mng
</span><span class='line'>&Operation=cluster_summary
</span><span class='line'>&ClusterId=251005746bc0f03q8u93j
</span><span class='line'>&GroupId=0
</span><span class='line'>&GroupName=liulanOrg
</span><span class='line'>&&lt;公共请求参数&gt;</span></code></pre></td></tr></table></div></figure>


<p><strong>输出示例</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{
</span><span class='line'>  "Response": {
</span><span class='line'>    "ClientCertCount": 2,
</span><span class='line'>    "JoinChannelCount": 1,
</span><span class='line'>    "MyChaincodeCount": 1,
</span><span class='line'>    "MyChannelCount": 1,
</span><span class='line'>    "MyGroupCount": 1,
</span><span class='line'>    "MyPeerCount": 2,
</span><span class='line'>    "NoneChannelCount": 0,
</span><span class='line'>    "OrderCertCount": 0,
</span><span class='line'>    "OtherChaincodeCount": 0,
</span><span class='line'>    "OtherChannelCount": 0,
</span><span class='line'>    "OtherGroupCount": 0,
</span><span class='line'>    "OtherPeerCount": 0,
</span><span class='line'>    "PeerCertCount": 2,
</span><span class='line'>    "RecentChaincodeCount": 1,
</span><span class='line'>    "RequestId": "8646a1d8-bae3-4b41-8732-06b8c004eaa5",
</span><span class='line'>    "TlsCertCount": 4,
</span><span class='line'>    "TotalCertCount": 8,
</span><span class='line'>    "TotalChaincodeCount": 1,
</span><span class='line'>    "TotalChannelCount": 1,
</span><span class='line'>    "TotalGroupCount": 1,
</span><span class='line'>    "TotalPeerCount": 2
</span><span class='line'>  }
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<h5>3.3.3、获取最新交易列表</h5>

<p>这个接口也是获取交易数据，只是他获取的是最新上链的数据列表，总体跟3.3.1的接口很相似，下面是示例</p>

<p><strong>输入示例</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>https://tbaas.tencentcloudapi.com/?Action=GetLatesdTransactionList
</span><span class='line'>&Module=transaction
</span><span class='line'>&Operation=latest_transaction_list
</span><span class='line'>&GroupId=0&ChannelId=0
</span><span class='line'>&LatestBlockNumber=5
</span><span class='line'>&GroupName=liulanOrg
</span><span class='line'>&ChannelName=kylotst
</span><span class='line'>&ClusterId=251005746bc0f03q8u93j
</span><span class='line'>&Offset=0
</span><span class='line'>&Limit=10
</span><span class='line'>&&lt;公共请求参数&gt;</span></code></pre></td></tr></table></div></figure>


<p><strong>输出示例</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{
</span><span class='line'>  "Response": {
</span><span class='line'>    "RequestId": "68cd2009-6a2b-481e-850e-08522a546221",
</span><span class='line'>    "TotalCount": 5,
</span><span class='line'>    "TransactionList": [
</span><span class='line'>      {
</span><span class='line'>        "BlockHeight": 6,
</span><span class='line'>        "BlockId": 5,
</span><span class='line'>        "CreateOrgName": "liulanOrg",
</span><span class='line'>        "CreateTime": "2019-04-24 11:39:52",
</span><span class='line'>        "TransactionHash": "da6a44da08bda02fb94b2b3fb684350a7f636044f348dbed9804f1dc143d2a01",
</span><span class='line'>        "TransactionId": "4ea1f77d1c2622f6672e37c611a0542dc9e21b15298b03de4127df454a17a457",
</span><span class='line'>        "TransactionStatus": "VALID",
</span><span class='line'>        "TransactionType": "ENDORSER_TRANSACTION"
</span><span class='line'>      },
</span><span class='line'>      {
</span><span class='line'>        "BlockHeight": 5,
</span><span class='line'>        "BlockId": 4,
</span><span class='line'>        "CreateOrgName": "liulanOrg",
</span><span class='line'>        "CreateTime": "2019-04-24 11:39:25",
</span><span class='line'>        "TransactionHash": "6e8a88088e1c0b111f7ff0f74e7891a15c5c32cd1fa68d8e5f8d11637fd4ca04",
</span><span class='line'>        "TransactionId": "9f2e40a4443d9928ed9b8266e893ac90ed00381227994281833ecd4393d40b15",
</span><span class='line'>        "TransactionStatus": "VALID",
</span><span class='line'>        "TransactionType": "ENDORSER_TRANSACTION"
</span><span class='line'>      },
</span><span class='line'>      {
</span><span class='line'>        "BlockHeight": 4,
</span><span class='line'>        "BlockId": 3,
</span><span class='line'>        "CreateOrgName": "liulanOrg",
</span><span class='line'>        "CreateTime": "2019-04-23 19:15:59",
</span><span class='line'>        "TransactionHash": "421234c8ad48052f202a262f1fe739b963831c423b2d0028ba7496eca837cac9",
</span><span class='line'>        "TransactionId": "bf2cdfd82a7b9a9a5ce135ef41687f3f04496c41575e2994fae99b58bec80754",
</span><span class='line'>        "TransactionStatus": "VALID",
</span><span class='line'>        "TransactionType": "ENDORSER_TRANSACTION"
</span><span class='line'>      },
</span><span class='line'>      {
</span><span class='line'>        "BlockHeight": 3,
</span><span class='line'>        "BlockId": 2,
</span><span class='line'>        "CreateOrgName": "liulanOrg",
</span><span class='line'>        "CreateTime": "2019-04-23 19:14:23",
</span><span class='line'>        "TransactionHash": "57407887234a4645c7b339aea5e94d3cf5f017f5eb05037a2c12fecf9d4fd6ae",
</span><span class='line'>        "TransactionId": "71594843087d3435c2aa74f69d9d995ed97fff4951778b86956c2c069691fb54",
</span><span class='line'>        "TransactionStatus": "VALID",
</span><span class='line'>        "TransactionType": "ENDORSER_TRANSACTION"
</span><span class='line'>      },
</span><span class='line'>      {
</span><span class='line'>        "BlockHeight": 2,
</span><span class='line'>        "BlockId": 1,
</span><span class='line'>        "CreateOrgName": "liulanOrg",
</span><span class='line'>        "CreateTime": "2019-04-23 14:34:29",
</span><span class='line'>        "TransactionHash": "9d798fe9f0eeaf5193ec1f9dc21e930bf3232820ddc1db18625b9f02bd35f54a",
</span><span class='line'>        "TransactionId": "4ee11735f87b34673ea88c162e71b20fb71f798e89231e45bc0fbc6b9f09d02c",
</span><span class='line'>        "TransactionStatus": "VALID",
</span><span class='line'>        "TransactionType": "ENDORSER_TRANSACTION"
</span><span class='line'>      }
</span><span class='line'>    ]
</span><span class='line'>  }
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<h3>4、需要注意的问题</h3>

<p>上面是整个TBaaS的使用和对接过程，可以说基于TBaaS平台，联盟链的开发成本降了很多，但在整个开发过程中，有以下几个问题需要注意。</p>

<h5>4.1、哪些数据适合存储在链上？</h5>

<p>参与方最好不要将一些敏感信息上链，例如用户身份信息、用户联系方式、资金信息等。适合存储在链上的数据可划分为以下方面：</p>

<ul>
<li>项目由多方参与，且数据需要多方达成共识才能生成。</li>
<li>项目由多方参与，且数据需要在多方之间内共享。</li>
<li>需要特定参与方对真实性进行背书的数据。</li>
<li>有直接或者间接价值的数据。</li>
</ul>


<h5>4.2、上链的性能问题</h5>

<p>从TBaaS的官方文档上看，15节点的区块链网络中实现单通道超过7000TPS，官方并没有说明具体服务器的配置，之前我们做过测试，Farbic网络中，8G内存，4核心CPU，4个节点，单通道请求一般是200-300TPS左右，在实际应用中，一开始我们的节点数没有这么多，还有服务器的具体配置与应用环境，在对接的过程需要注意请求并发量，防止上链的性能问题。</p>

<h5>4.3、上链的数据隐私问题</h5>

<p>目前TBaaS针对Fabric的数据隐私问题，有如下不同程序保护</p>

<ul>
<li>使用多链支持，将区块链分为若干通道+腾讯云用户系统，通道与通道之间的数据隔离存储和传输，数据只能被此通道的参与方访问。</li>
<li>参与方可以仅将数据的摘要值或者加密后的密文上链。该方式需要保证数据的访问方能够根据摘要值获取到原始数据，或者拥有对密文进行解密的密钥。</li>
<li>通过在智能合约中定义规则，只允许特定的角色有权限访问数据。</li>
</ul>


<p><a href="http://blog.1nongfu.com/%E8%85%BE%E8%AE%AF%E4%BA%91%E5%8C%BA%E5%9D%97%E9%93%BE%E6%9C%8D%E5%8A%A1%E5%B9%B3%E5%8F%B0%E4%BB%8B%E7%BB%8D%E5%8F%8A%E6%8E%A5%E5%85%A5.pdf">点击下载PDF版</a></p>

<div align="right">
  徐耀&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>
  最后更新时间：2019-06-06
</div>


<p></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[ES6中如何删除数组中的重复项]]></title>
    <link href="http://xuyao.club/blog/2019/02/15/how-to-remove-array-duplicates-in-es6/"/>
    <updated>2019-02-15T16:00:59+08:00</updated>
    <id>http://xuyao.club/blog/2019/02/15/how-to-remove-array-duplicates-in-es6</id>
    <content type="html"><![CDATA[<p>&emsp; ES6中，如何删除一个数组中的重复数据呢，以下是我总结的，从数组中过滤掉重复项并且返回唯一值的三种方法。我最喜欢的是使用Set因为它是最简单和最简单的😁</p>

<!-- more -->


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>const array = ['🐷',1, 2,'🐷','🐷', 3]
</span><span class='line'>
</span><span class='line'>// 1: 'Set'
</span><span class='line'>[... new Set(array)]
</span><span class='line'>
</span><span class='line'>// 2: 'Filter'
</span><span class='line'>array.filter((item, index) =&gt; array.indexOf(item) === index)
</span><span class='line'>
</span><span class='line'>// 3: 'Reduce'
</span><span class='line'>array.reduce((unique, item) =&gt; unique.includes(item) ? unique : [...unique, item], [])
</span><span class='line'>
</span><span class='line'>// 返回结果
</span><span class='line'>[ '🐷', 1, 2, 3 ]</span></code></pre></td></tr></table></div></figure>


<h4>1. 使用Set</h4>

<p>我先解释一下什么是Set:</p>

<blockquote><p>Set是ES6中引入的新数据对象。Set只允许您存储唯一值。当传入数组时，它会删除任何重复的值。</p></blockquote>

<p>ok，我们重新回到刚才的代码来分析一下发生了什么事情，（上面的代码）做了两件事情。
1、首先，我们通过传递一个数组来创建了一个新的Set，因为Set只允许存储唯一的值，所以数组中那些重复的值会被删除。
2、创建一个新的Set对象后，重复值已经被删除了，现在我们使用&hellip;运算符，将其转换回数组。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>const array = ['🐷',1, 2,'🐷','🐷', 3]
</span><span class='line'>
</span><span class='line'>// Step 1
</span><span class='line'>const uniqueSet = new Set(array)
</span><span class='line'># Set { '🐷', 1, 2, 3 }
</span><span class='line'>
</span><span class='line'>// Step 2
</span><span class='line'>const backToArray = [...uniqueSet]
</span><span class='line'># [ '🐷', 1, 2, 3 ]</span></code></pre></td></tr></table></div></figure>


<h5>使用Array.from 将Set转换为Array</h5>

<p>或者你也可以使用Array.from将Set转化为数组</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>const array = ['🐷',1, 2,'🐷','🐷', 3]
</span><span class='line'>
</span><span class='line'>Array.from(new Set(array))
</span><span class='line'># [ '🐷', 1, 2, 3 ]</span></code></pre></td></tr></table></div></figure>


<h4>2.使用Filter</h4>

<p>为了便于理解，我们先来看下indexOf和filter会做什么事情</p>

<h5>indexOf</h5>

<p>indexOf方法会将我们提供的参数，在数组中找到该元素的第一个索引值并返回。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>const array = ['🐷',1, 2,'🐷','🐷', 3]
</span><span class='line'>
</span><span class='line'>array.indexOf('🐷') #=&gt; 0
</span><span class='line'>array.indexOf(1) #=&gt; 1
</span><span class='line'>array.indexOf(2) #=&gt; 2
</span><span class='line'>array.indexOf(3) #=&gt; 5</span></code></pre></td></tr></table></div></figure>


<h4>filter</h4>

<p>filter()方法会根据我们传递的条件，来创建一个新的元素数组。换句话说，如果元素通过并返回true，它将包含在已经过滤的数组中。任何失败元素或者返回为false的，都不会在过滤后的数组中。
让我们一步步来分析数组循环时发生的事情</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>const array = ['🐷',1, 2,'🐷','🐷', 3]
</span><span class='line'>
</span><span class='line'>array.filter((item, index) =&gt; {
</span><span class='line'>  console.log(
</span><span class='line'>      // a. Item
</span><span class='line'>      item,
</span><span class='line'>      // b. Index
</span><span class='line'>      index,
</span><span class='line'>      // c. IndexOf
</span><span class='line'>      array.indexOf(item),
</span><span class='line'>      // d. Condition
</span><span class='line'>      array.indexOf(item) === index,
</span><span class='line'>  );
</span><span class='line'>  return array.indexOf(item) === index
</span><span class='line'>})</span></code></pre></td></tr></table></div></figure>


<p>以下是上面显示的console.log的输出。重复项是索引与indexOf不匹配的位置。因此，在这些情况下，条件将为false，不会包含在我们的过滤数组中。
<img src="https://upload-images.jianshu.io/upload_images/1796624-e1340356c5bd98fe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" /></p>

<h4>检索重复值</h4>

<p>我们还可以使用filter方法从数组中检索重复值。我们可以通过简单地修改我们的条件就可以做到：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>const array = ['🐷',1, 2,'🐷','🐷', 3]
</span><span class='line'>array.filter((item, index) =&gt; array.indexOf(item) !== index)
</span><span class='line'># [ '🐷', '🐷' ]</span></code></pre></td></tr></table></div></figure>


<p>再次，如果我们一步一来执行上面的代码，可以查看输出：
<img src="https://upload-images.jianshu.io/upload_images/1796624-37f124574645e5c6.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" /></p>

<h4>3.使用 reduce</h4>

<p>reduce方法用于减少数组的元素，并根据您传递的某些reducer函数将它们组合成最终数组。</p>

<p>在这个例子中，我们的reducer函数检查我们的最终数组是否包含该项。如果没有，请将该项目推送到我们的最终数组中。否则，跳过该元素并按原样返回我们的最终数组（基本上跳过该元素）。</p>

<p>reduce总是有点难以理解，所以让我们进入每个案例并查看输出：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>array.reduce((unique, item) =&gt; {
</span><span class='line'>  console.log(
</span><span class='line'>      // a. Item
</span><span class='line'>      item,
</span><span class='line'>      // b. Final Array (Accumulator)
</span><span class='line'>      unique,
</span><span class='line'>      // c. Condition (Remember it only get pushed if this return 'false')
</span><span class='line'>      unique.includes(item),
</span><span class='line'>      // d. Reducer Function Result
</span><span class='line'>      unique.includes(item) ? unique : [...unique, item],
</span><span class='line'>  );
</span><span class='line'>  unique.includes(item) ? unique : [...unique, item]
</span><span class='line'>}, [])
</span><span class='line'>
</span><span class='line'># [ '🐷', '🐷' ]</span></code></pre></td></tr></table></div></figure>


<p>这是console.log的输出：
<img src="https://upload-images.jianshu.io/upload_images/1796624-8de3d95d35e6bf25.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" /></p>

<h4>参考资料</h4>

<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set">MDN Web Docs — Set</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter">MDN Web Docs — Filter</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce">MDN Web Docs — Reduce</a></li>
<li><a href="https://gist.github.com/telekosmos/3b62a31a5c43f40849bb">GitHubGist: Remove duplicates from JS array</a></li>
<li><a href="https://codehandbook.org/how-to-remove-duplicates-from-javascript-array/">CodeHandbook: How to Remove Duplicates from JavaScript Array</a></li>
</ul>


<h4>说明</h4>

<p>本文翻译自<a href="https://medium.com/@samanthaming">Samantha Ming</a>的博客，原文地址<br/>
<a href="https://medium.com/dailyjs/how-to-remove-array-duplicates-in-es6-5daa8789641c">https://medium.com/dailyjs/how-to-remove-array-duplicates-in-es6-5daa8789641c</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Fabric动态增加节点（Peer）]]></title>
    <link href="http://xuyao.club/blog/2019/01/10/fabric-adds-nodes-dynamically/"/>
    <updated>2019-01-10T11:00:22+08:00</updated>
    <id>http://xuyao.club/blog/2019/01/10/fabric-adds-nodes-dynamically</id>
    <content type="html"><![CDATA[<h5>前言</h5>

<p> &emsp; 在实际项目中，因为项目的需求变动，一般都会对fabric网络做一个修改，最常见的变动就是在现有的Fabric网络中增加一个节点，现在以之前搭建的fabric网络（版本1.1），balance-transfer为例做个介绍，整个过程其实也很简单，生成节点证书，增加新节点的docker配置文件并启动相应的服务，然后将新节点加到现有的channel当中，并在节点上安装智能合约（Chaincode），下午详情讲一下具体的操作步骤。</p>

<h4>1、修改crypto-config.yaml文件并生成对应的节点证书。</h4>

<p>首先我们确认我们需要在Org2里增加节点，那么我们在crypto-config.yaml文件里找到对应Org2的配置，把Template字段里的count参数修改成2，意思就是在此组织下生成两个节点，配置文件如下</p>

<!-- more -->


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>- Name: Org2
</span><span class='line'>    Domain: org2.xuyao.com
</span><span class='line'>    EnableNodeOUs: true
</span><span class='line'>    Template:
</span><span class='line'>      Count: 2
</span><span class='line'>    Users:
</span><span class='line'>      Count: 1</span></code></pre></td></tr></table></div></figure>


<p>修改好配置文件后，我们现在使用cryptogen来生成证书，在在artifacts/channel目录下执行：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>./cryptogen extend --config=./crypto-config.yaml</span></code></pre></td></tr></table></div></figure>


<p>这样我们就为新节点生成了证书，可以到Org2相应的目录上查看，发现已经新生成了一个节点，加上之前那个，一共有两个节点。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>peer0.org2.mbasechain.com peer1.org2.mbasechain.com</span></code></pre></td></tr></table></div></figure>


<h4>2、配置docker-compose文件并启动节点容器</h4>

<p>接下来我们需要新增一个doceker-compose有配置文件，用来启动一个新节点容器，我们将新节点的配置文件全名为：Org2Peer1.yaml</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>version: '2'
</span><span class='line'>
</span><span class='line'>services:
</span><span class='line'>
</span><span class='line'>  couchdb:
</span><span class='line'>    container_name: couchdb
</span><span class='line'>    image: hyperledger/fabric-couchdb:latest
</span><span class='line'>    ports:
</span><span class='line'>      - "5984:5984"
</span><span class='line'>
</span><span class='line'>  peer1.org1.xuyao.com:
</span><span class='line'>    container_name: peer1.org1.xuyao.com
</span><span class='line'>    image: hyperledger/fabric-peer:latest
</span><span class='line'>    environment:
</span><span class='line'>      - CORE_PEER_ID=peer1.org1.xuyao.com
</span><span class='line'>      - CORE_PEER_LOCALMSPID=Org1MSP
</span><span class='line'>      - CORE_PEER_ADDRESS=peer1.org1.xuyao.com:7051
</span><span class='line'>      - CORE_LEDGER_STATE_STATEDATABASE=CouchDB
</span><span class='line'>      - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
</span><span class='line'>      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
</span><span class='line'>      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=artifacts_default
</span><span class='line'>      - CORE_LOGGING_LEVEL=debug
</span><span class='line'>      - CORE_PEER_GOSSIP_USELEADERELECTION=true
</span><span class='line'>      - CORE_PEER_GOSSIP_ORGLEADER=false
</span><span class='line'>      - GODEBUG=netdns=go
</span><span class='line'>      # The following setting skips the gossip handshake since we are
</span><span class='line'>      # are not doing mutual TLS
</span><span class='line'>      - CORE_PEER_GOSSIP_SKIPHANDSHAKE=true
</span><span class='line'>      - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/crypto/peer/msp
</span><span class='line'>      - CORE_PEER_TLS_ENABLED=true
</span><span class='line'>      - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/crypto/peer/tls/server.key
</span><span class='line'>      - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/crypto/peer/tls/server.crt
</span><span class='line'>      - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/crypto/peer/tls/ca.crt
</span><span class='line'>    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
</span><span class='line'>    command: peer node start
</span><span class='line'>    ports:
</span><span class='line'>      - 7051:7051
</span><span class='line'>      - 7053:7053
</span><span class='line'>    volumes:
</span><span class='line'>        - /var/run/:/host/var/run/
</span><span class='line'>        - ./channel/crypto-config/peerOrganizations/org1.mbasechain.com/peers/peer0.org1.xuyao.com/:/etc/hyperledger/crypto/peer
</span><span class='line'>        - ../mount/peer0.org1.xuyao.com/var/hyperledger/production:/var/hyperledger/production
</span><span class='line'>    depends_on:
</span><span class='line'>        - couchdb</span></code></pre></td></tr></table></div></figure>


<p>这个配置文件跟之前的peer节点的配置一样，只要改下相应的参数即可，接下来我们就来启动这个节点。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>docker-compose -f Org2Peer1.yaml up -d</span></code></pre></td></tr></table></div></figure>


<p>启动过程也和之前的一样。</p>

<h4>3、修改network-config.json配置文件</h4>

<p>启动节点后，我们需要配置network-config.json，让应用与节点之前通信，在peers那块增加一个通讯节点就可以</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>peer1.org2.xuyao.com:
</span><span class='line'>    url: grpcs://127.0.0.1:10051
</span><span class='line'>    eventUrl: grpcs://127.0.0.1:10053
</span><span class='line'>    grpcOptions:
</span><span class='line'>      ssl-target-name-override: peer1.org2.xuyao.com
</span><span class='line'>    tlsCACerts:
</span><span class='line'>      path: artifacts/channel/crypto-config/peerOrganizations/org4.mbasechain.com/peers/peer1.org2.xuyao.com/tls/ca.crt</span></code></pre></td></tr></table></div></figure>


<p>修改配置后，我们启动balance-transfer,运行runApp.sh,将项目跑起来。</p>

<h4>4、将新节点加入到所需的Channel中</h4>

<p>接下来我们需要将新节点加到某个Channel里，首先我们通过注册接口，在Org2里拿到用户的Token,再拿此Token请求中入Channel接口</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -s -X POST \
</span><span class='line'>  http://localhost:4000/channels/mychannel/peers \
</span><span class='line'>  -H "authorization: Bearer $ORG2_TOKEN" \
</span><span class='line'>  -H "content-type: application/json" \
</span><span class='line'>  -d '{
</span><span class='line'>  "peers": ["peer1.org2.xuyao.com"]
</span><span class='line'>}'</span></code></pre></td></tr></table></div></figure>


<h4>5、安装Chaincode</h4>

<p>加入channel后，peer3已经可以参与记账，但是不能指定该节点进行查询或交易，这时候需要发起请求安装chaincode：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -s -X POST \
</span><span class='line'>    http://localhost:$PORT/chaincodes \
</span><span class='line'>    -H "authorization: Bearer $ORG1_TOKEN" \
</span><span class='line'>    -H "content-type: application/json" \
</span><span class='line'>    -d '{
</span><span class='line'>    "peers": ["peer1.org2.xuyao.com"],
</span><span class='line'>    "chaincodeName":"mycc",
</span><span class='line'>    "chaincodePath":"github.com/example_cc",
</span><span class='line'>    "chaincodeVersion":"v0"
</span><span class='line'>  }'</span></code></pre></td></tr></table></div></figure>


<p>安装成功后指定新节点进行查询或交易操作，会自动生成该节点的chaincode镜像，并启动容器运行chaincode。在已有组织中新加节点的操作到这里就全部完成了！</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Fabric多台服务器的部署(五)]]></title>
    <link href="http://xuyao.club/blog/2018/12/29/deployment-of-fabric-multiple-servers-iiiii/"/>
    <updated>2018-12-29T16:57:34+08:00</updated>
    <id>http://xuyao.club/blog/2018/12/29/deployment-of-fabric-multiple-servers-iiiii</id>
    <content type="html"><![CDATA[<h4>8、Fabric 浏览器的部署</h4>

<h6>8.1 环境准备</h6>

<p>1、nodejs安装，在第1节里已经说过node的安装，需要注意的是node版本应该是v9.x以下。<br/>
2、PostgreSQL的安装，浏览器会把监听到的数据存储在pg里，所以需要安装pg数据。</p>

<!-- more -->


<p>ubuntu使用直接安装</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>sudo apt update
</span><span class='line'>sudo apt install postgresql postgresql-contrib</span></code></pre></td></tr></table></div></figure>


<p>安装好后，可以使用cli查看一下</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#切换用户
</span><span class='line'>sudo -i -u postgres
</span><span class='line'>#进入控制台
</span><span class='line'>psql
</span><span class='line'>#退出
</span><span class='line'>postgres=# \q</span></code></pre></td></tr></table></div></figure>


<p>3、安装Jq，jq是一个轻量级且灵活的命令行JSON处理器，安装很简单，见官网<a href="https://stedolan.github.io/jq/download/">https://stedolan.github.io/jq/download/</a></p>

<h5>8.2、下载浏览器源码</h5>

<p>&emsp; 在github上下载fabric 浏览器的源码，<a href="https://github.com/hyperledger/blockchain-explorer">https://github.com/hyperledger/blockchain-explorer</a>，把源码拉下来，根据自己的需要选择不用的版本，我目前使用的是1.1版本，所以我切换到对应的1.1分支上。</p>

<h5>8.3、修改配置</h5>

<h6>8.3.1 配置postgresql数据库</h6>

<p>&emsp; 进入 app/persistence/postgreSQL/db/文件夹，找到pgconfig.json配置文件，修改连接pg数据库的配置，默认配置为</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{
</span><span class='line'>  "pg": {
</span><span class='line'>    "host": "127.0.0.1",
</span><span class='line'>    "port": "5432",
</span><span class='line'>    "database": "fabricexplorer",
</span><span class='line'>    "username": "hppoc",
</span><span class='line'>    "passwd": "password"
</span><span class='line'>  }
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<p>修改支运行createdb.sh脚本文件，创建浏览器所需的数据库和表名。</p>

<h6>8.3.2、配置启动abric浏览器文件</h6>

<p>进入 blockchain-explorer/app/platform/fabric，找到对应的config.json文件，配置对应的fabric网络信息，包括节点的请求接口，及监听接口，不同浏览器版本这个配置文件不太一样，1.1版本的配置文件如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{
</span><span class='line'>  "network-config": {
</span><span class='line'>    "org1": {
</span><span class='line'>      "name": "peerOrg1",
</span><span class='line'>      "mspid": "Org1MSP",
</span><span class='line'>      "peer1": {
</span><span class='line'>        "requests": "grpcs://localhost:7051",
</span><span class='line'>        "events": "grpcs://localhost:7053",
</span><span class='line'>        "server-hostname": "peer0.org1.mbasechain.com",
</span><span class='line'>        "tls_cacerts": "/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/peerOrganizations/org1.mbasechain.com/peers/peer0.org1.mbasechain.com/tls/ca.crt"
</span><span class='line'>      },
</span><span class='line'>      "admin": {
</span><span class='line'>        "key": "/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/peerOrganizations/org1.mbasechain.com/users/Admin@org1.mbasechain.com/msp/keystore",
</span><span class='line'>        "cert": "/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/peerOrganizations/org1.mbasechain.com/users/Admin@org1.mbasechain.com/msp/signcerts"
</span><span class='line'>      }
</span><span class='line'>    },
</span><span class='line'>    "org2": {
</span><span class='line'>      "name": "peerOrg2",
</span><span class='line'>      "mspid": "Org2MSP",
</span><span class='line'>      "peer1": {
</span><span class='line'>        "requests": "grpcs://localhost:7056",
</span><span class='line'>        "events": "grpcs://localhost:7058",
</span><span class='line'>        "server-hostname": "peer0.org2.mbasechain.com",
</span><span class='line'>        "tls_cacerts": "/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/peerOrganizations/org2.mbasechain.com/peers/peer0.org2.mbasechain.com/tls/ca.crt"
</span><span class='line'>      },
</span><span class='line'>      "admin": {
</span><span class='line'>        "key": "/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/peerOrganizations/org2.mbasechain.com/users/Admin@org2.mbasechain.com/msp/keystore",
</span><span class='line'>        "cert": "/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/peerOrganizations/org2.mbasechain.com/users/Admin@org2.mbasechain.com/msp/signcerts"
</span><span class='line'>      }
</span><span class='line'>    },
</span><span class='line'>    "org3": {
</span><span class='line'>      "name": "peerOrg3",
</span><span class='line'>      "mspid": "Org3MSP",
</span><span class='line'>      "peer1": {
</span><span class='line'>        "requests": "grpcs://localhost:8051",
</span><span class='line'>        "events": "grpcs://localhost:8053",
</span><span class='line'>        "server-hostname": "peer0.org3.mbasechain.com",
</span><span class='line'>        "tls_cacerts": "/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/peerOrganizations/org3.mbasechain.com/peers/peer0.org3.mbasechain.com/tls/ca.crt"
</span><span class='line'>      },
</span><span class='line'>      "admin": {
</span><span class='line'>        "key": "/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/peerOrganizations/org3.mbasechain.com/users/Admin@org3.mbasechain.com/msp/keystore",
</span><span class='line'>        "cert": "/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/peerOrganizations/org3.mbasechain.com/users/Admin@org3.mbasechain.com/msp/signcerts"
</span><span class='line'>      }
</span><span class='line'>    },
</span><span class='line'>    "org4": {
</span><span class='line'>      "name": "peerOrg4",
</span><span class='line'>      "mspid": "Org4MSP",
</span><span class='line'>      "peer1": {
</span><span class='line'>        "requests": "grpcs://localhost:8056",
</span><span class='line'>        "events": "grpcs://localhost:9058",
</span><span class='line'>        "server-hostname": "peer0.org4.mbasechain.com",
</span><span class='line'>        "tls_cacerts": "/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/peerOrganizations/org4.mbasechain.com/peers/peer0.org4.mbasechain.com/tls/ca.crt"
</span><span class='line'>      },
</span><span class='line'>      "admin": {
</span><span class='line'>        "key": "/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/peerOrganizations/org4.mbasechain.com/users/Admin@org4.mbasechain.com/msp/keystore",
</span><span class='line'>        "cert": "/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/peerOrganizations/org4.mbasechain.com/users/Admin@org4.mbasechain.com/msp/signcerts"
</span><span class='line'>      }
</span><span class='line'>    }
</span><span class='line'>  },
</span><span class='line'>  "channel": "mychannel",
</span><span class='line'>  "orderers":[
</span><span class='line'>    {
</span><span class='line'>      "mspid": "OrdererMSP",
</span><span class='line'>      "server-hostname":"orderer1.mbasechain.com",
</span><span class='line'>      "requests":"grpcs://localhost:7050",
</span><span class='line'>      "tls_cacerts":"/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/ordererOrganizations/mbasechain.com/orderers/orderer1.mbasechain.com/tls/ca.crt"
</span><span class='line'>    },
</span><span class='line'>    {
</span><span class='line'>      "mspid": "OrdererMSP",
</span><span class='line'>      "server-hostname":"orderer2.mbasechain.com",
</span><span class='line'>      "requests":"grpcs://localhost:8050",
</span><span class='line'>      "tls_cacerts":"/Users/xuyao/Workspaces/trace_kingland/artifacts/channel/crypto-config/ordererOrganizations/mbasechain.com/orderers/orderer2.mbasechain.com/tls/ca.crt"
</span><span class='line'>    }
</span><span class='line'>  ],
</span><span class='line'>  "keyValueStore": "/tmp/fabric-client-kvs",
</span><span class='line'>  "configtxgenToolPath": "/Users/xuyao/Workspaces/goworkspace/src/blockchain/fabric/v1.2.0/fabric-samples/bin",
</span><span class='line'>  "SYNC_START_DATE_FORMAT":"YYYY/MM/DD",
</span><span class='line'>  "syncStartDate":"2018/01/01",
</span><span class='line'>  "eventWaitTime": "30000",
</span><span class='line'>  "license": "Apache-2.0",
</span><span class='line'>  "version": "1.1"
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<p>配置各节点的信息及tls的ca证书，管理员的私钥及证书等信息。</p>

<h6>8.3.3、构建node项目</h6>

<p>1、进入blockchain-explorer/ 下，使用npm install 安装项目所需package，<br/>
2、再进入blockchain-explorer/app/test/下，使用npm install 安装测试项目里的所需包，再跑测试脚本</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#安装包
</span><span class='line'>npm install
</span><span class='line'>
</span><span class='line'>#运行测试脚本
</span><span class='line'>npm run test</span></code></pre></td></tr></table></div></figure>


<p>3、进入client/ 使用npm install 命令安装包</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>npm install
</span><span class='line'>
</span><span class='line'>npm test -- -u --coverage
</span><span class='line'>
</span><span class='line'>npm run build</span></code></pre></td></tr></table></div></figure>


<h5>8.4、启动fabric浏览器</h5>

<p>&emsp; 使用脚本./start.sh来启动项目，启动成功后，可以打开浏览器查看一下.
<img src="https://upload-images.jianshu.io/upload_images/1796624-c1112936dd3eabf3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="浏览器截图" />
其中做了一些汉化。</p>

<h5>已完结</h5>

<h5>参考资料</h5>

<p>1、<a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-18-04">https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-18-04</a><br/>
2、<a href="https://github.com/hyperledger/blockchain-explorer">https://github.com/hyperledger/blockchain-explorer</a><br/>
3、<a href="https://stedolan.github.io/jq/download/">https://stedolan.github.io/jq/download/</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Fabric多台服务器的部署(四)]]></title>
    <link href="http://xuyao.club/blog/2018/12/29/deployment-of-fabric-multiple-servers-iiii/"/>
    <updated>2018-12-29T16:51:08+08:00</updated>
    <id>http://xuyao.club/blog/2018/12/29/deployment-of-fabric-multiple-servers-iiii</id>
    <content type="html"><![CDATA[<h4>7、创建channel和chaincode</h4>

<p> &emsp; 之前我们说过，本项目是一个nodejs的项目，是根据<a href="https://github.com/hyperledger/fabric-samples">https://github.com/hyperledger/fabric-samples</a>里的balance_transfer稍作修改来的，所以这里我们创建channel和chaincode，包括数据上链都会用nodejs sdk来做。</p>

<h6>7.1、启动nodejs服务</h6>

<p> &emsp;进入我们的trace_wine项目，使用npm安装项目所需的package,</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>npm install</span></code></pre></td></tr></table></div></figure>


<p>安装完后，我们现在要启动node服务，我们可以看下，当前目录下面的个runApp.sh的脚本文件，看下里面内容就知道，这是个启动node服务的脚本</p>

<!-- more -->


<p><img src="https://upload-images.jianshu.io/upload_images/1796624-895fa4b8dae442f8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="项目的基本文件" />
现在我们来运行一下这个脚本文件，使用命令</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>./runApp.sh</span></code></pre></td></tr></table></div></figure>


<p>查看是否启动成功，进入项目下的logs文件夹，找到当前的日志文件，打开看一下</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>tail -f 2018-11-28.log
</span><span class='line'>
</span><span class='line'>[2018-11-28 15:06:48.699] [INFO] Helper - Successfully loaded member from persistence
</span><span class='line'>[2018-11-28 15:07:15.485] [INFO] app - ****************** SERVER STARTED ************************
</span><span class='line'>[2018-11-28 15:07:15.488] [INFO] app - ***************  http://localhost:4000  ******************</span></code></pre></td></tr></table></div></figure>


<p>可以看到node服务已经启动成功，且端口号为4000，具体的文档可查看官方的<a href="https://github.com/hyperledger/fabric-samples/blob/release-1.3/balance-transfer/README.md">readme</a></p>

<h6>7.2、创建Ca用户</h6>

<p> &emsp;Fabric CA为每个上链、查询者提供了注册用户，生成用户证书(ECerts)的功能，我们现在可以通过REST APIs来与ca server交互，我们先看下node里注册用户，生成证书的代码</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>///////////////////////////////////////////////////////////////////////////////
</span><span class='line'>///////////////////////// REST ENDPOINTS START HERE ///////////////////////////
</span><span class='line'>///////////////////////////////////////////////////////////////////////////////
</span><span class='line'>// Register and enroll user
</span><span class='line'>app.post('/users', async function(req, res) {
</span><span class='line'>  var username = req.body.username;
</span><span class='line'>  var orgName = req.body.orgName;
</span><span class='line'>  logger.debug('End point : /users');
</span><span class='line'>  logger.debug('User name : ' + username);
</span><span class='line'>  logger.debug('Org name  : ' + orgName);
</span><span class='line'>  if (!username) {
</span><span class='line'>      res.json(getErrorMessage('\'username\''));
</span><span class='line'>      return;
</span><span class='line'>  }
</span><span class='line'>  if (!orgName) {
</span><span class='line'>      res.json(getErrorMessage('\'orgName\''));
</span><span class='line'>      return;
</span><span class='line'>  }
</span><span class='line'>  var token = jwt.sign({
</span><span class='line'>      exp: Math.floor(Date.now() / 1000) + parseInt(hfc.getConfigSetting('jwt_expiretime')),
</span><span class='line'>      username: username,
</span><span class='line'>      orgName: orgName
</span><span class='line'>  }, app.get('secret'));
</span><span class='line'>  let response = await helper.getRegisteredUser(username, orgName, true);
</span><span class='line'>  logger.debug('-- returned from registering the username %s for organization %s',username,orgName);
</span><span class='line'>  if (response && typeof response !== 'string') {
</span><span class='line'>      logger.debug('Successfully registered the username %s for organization %s',username,orgName);
</span><span class='line'>      response.token = token;
</span><span class='line'>      res.json(response);
</span><span class='line'>  } else {
</span><span class='line'>      logger.debug('Failed to register the username %s for organization %s with::%s',username,orgName,response);
</span><span class='line'>      res.json({success: false, message: response});
</span><span class='line'>  }
</span><span class='line'>
</span><span class='line'>});</span></code></pre></td></tr></table></div></figure>


<p>可以看到当用户传进来username和orgName时，node首先会使用jwt将他们生成一个Token，然后通过getRegisteredUser()方法生成用户的证书，最终将jwt生成的token返回给用户。<br/>
 &emsp;下面我们来调用一个这个接口</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#在Org1上注册和生成一个新用户，用户名为Jim
</span><span class='line'>curl -s -X POST http://localhost:4000/users -H "content-type: application/x-www-form-urlencoded" -d 'username=Jim&orgName=Org1'</span></code></pre></td></tr></table></div></figure>


<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#返回结果
</span><span class='line'>{
</span><span class='line'>  "success": true,
</span><span class='line'>  "secret": "RaxhMgevgJcm",
</span><span class='line'>  "message": "Jim enrolled Successfully",
</span><span class='line'>  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDQ1MjIxMTgsInVzZXJuYW1lIjoiZG9jIiwib3JnTmFtZSI6Ik9yZzEiLCJpYXQiOjE1NDQ0MzU3MTh9.X8DuFxUSmsRTe7v7iMft8A7LxzpvGyhnufBLQTZ3F8I"
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<p>上面的token就是我们想要的，之后每次请求接口都会用token来验证用户信息,更多的jwt信息，可以查看这里<a href="https://jwt.io/">https://jwt.io/</a>，另外用户生成的证书保存在服务器端，是标准的X.509证书格式，可以打开看一下这个证书</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{"name":"Jim","mspid":"Org1MSP","roles":null,"affiliation":"","enrollmentSecret":"",
</span><span class='line'>"enrollment":{"signingIdentity":"72d623e2104955b39ca6b6383a278b4b0a253e45a83b26044edf193563655367","
</span><span class='line'>identity":{"certificate":"
</span><span class='line'>-----BEGIN CERTIFICATE-----
</span><span class='line'>\nMIICkDCCAjegAwIBAgIUX+durkyChVVZ5LNZekudT17CcJUwCgYIKoZIzj0EAwIw\n
</span><span class='line'>eTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\n
</span><span class='line'>biBGcmFuY2lzY28xHDAaBgNVBAoTE29yZzEubWJhc2VjaGFpbi5jb20xHzAdBgNV\n
</span><span class='line'>BAMTFmNhLm9yZzEubWJhc2VjaGFpbi5jb20wHhcNMTgxMTIzMDk0NjAwWhcNMTkx\n
</span><span class='line'>MTIzMDk1MTAwWjBAMTAwDQYDVQQLEwZjbGllbnQwCwYDVQQLEwRvcmcxMBIGA1UE\n
</span><span class='line'>CxMLZGVwYXJ0bWVudDExDDAKBgNVBAMTA2RvYzBZMBMGByqGSM49AgEGCCqGSM49\n
</span><span class='line'>AwEHA0IABGUZz9n5KvXF9H0l4HSdCvegNE2A0pkk2w1oQLcJW9FaZvr7rBDG3/bl\nauV26OoHJX7Yo/N
</span><span class='line'>x2JyQrQzYRoPKfOWjgdUwgdIwDgYDVR0PAQH/BAQDAgeAMAwG\n
</span><span class='line'>A1UdEwEB/wQCMAAwHQYDVR0OBBYEFCGGAIKaIFfBpkYuR2rjxvGle+uRMCsGA1Ud\n
</span><span class='line'>IwQkMCKAIGyyJr5K7JgVQebL3WZ0ITnBFX6Ir+Bu37FvEuzDBWv1MGYGCCoDBAUG\n
</span><span class='line'>BwgBBFp7ImF0dHJzIjp7ImhmLkFmZmlsaWF0aW9uIjoib3JnMS5kZXBhcnRtZW50\n
</span><span class='line'>MSIsImhmLkVucm9sbG1lbnRJRCI6ImRvYyIsImhmLlR5cGUiOiJjbGllbnQifX0w\n
</span><span class='line'>CgYIKoZIzj0EAwIDRwAwRAIgYnTD6Pkx1+R4R77TztW3/oQb1h+5/3ELYtAsIuz7\n
</span><span class='line'>D8wCIBiOmE/uySQvkgzUcCsVRtaUMg0M9zioKBYHiPUxeNJo\n
</span><span class='line'>-----END CERTIFICATE-----\n"}}}%</span></code></pre></td></tr></table></div></figure>


<h6>7.2、创建Channel</h6>

<p> &emsp; 同样我们使用node服务提供的接口来创建Channel通道，具体创建channel的js代码可以看<a href="https://github.com/hyperledger/fabric-samples/blob/release-1.3/balance-transfer/app.js#L142">这里</a></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -s -X POST \
</span><span class='line'>  http://localhost:4000/channels \
</span><span class='line'>  -H "authorization: Bearer Token" \
</span><span class='line'>  -H "content-type: application/json" \
</span><span class='line'>  -d '{
</span><span class='line'>  "channelName":"mychannel",
</span><span class='line'>  "channelConfigPath":"../artifacts/channel/mychannel.tx"
</span><span class='line'>}'</span></code></pre></td></tr></table></div></figure>


<p>authorization里的Token是上面我们得到的token， channelName是我们要创建通道的名字，channelConfigPath指定mychannel.tx文件路径，创建成功，返回如下结果</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{"success":true,"message":"Channel 'mychannel' created Successfully"}</span></code></pre></td></tr></table></div></figure>


<h6>7.3、将Channel加入到Org里</h6>

<p> &emsp;现在我们需要将channel加入到Org里，这样Org就可以使用这个channel，同样是通过node接口来实现</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -s -X POST \
</span><span class='line'>  http://localhost:4000/channels/mychannel/peers \
</span><span class='line'>  -H "authorization: Bearer Token" \
</span><span class='line'>  -H "content-type: application/json" \
</span><span class='line'>  -d '{
</span><span class='line'>  "peers": ["peer0.org1.xuyao.com","peer1.org1.xuyao.com"]
</span><span class='line'>}'</span></code></pre></td></tr></table></div></figure>


<p>返回结果</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{"success":true,"message":"Successfully joined peers in organization Org1 to the channel:mychannel"}</span></code></pre></td></tr></table></div></figure>


<h6>7.4、编写和安装智能合约(chaincode)</h6>

<h6>7.4.1、编写智能合约(chaincode)</h6>

<p> &emsp;channel安装好后，我们需要编写智能合约，这里我贴一个我用go写的一个chaincode,功能很简单就是把数据上链，查询</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
<span class='line-number'>120</span>
<span class='line-number'>121</span>
<span class='line-number'>122</span>
<span class='line-number'>123</span>
<span class='line-number'>124</span>
<span class='line-number'>125</span>
<span class='line-number'>126</span>
<span class='line-number'>127</span>
<span class='line-number'>128</span>
<span class='line-number'>129</span>
<span class='line-number'>130</span>
<span class='line-number'>131</span>
<span class='line-number'>132</span>
<span class='line-number'>133</span>
<span class='line-number'>134</span>
<span class='line-number'>135</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>package main
</span><span class='line'>
</span><span class='line'>import (
</span><span class='line'>  "bytes"
</span><span class='line'>  "fmt"
</span><span class='line'>
</span><span class='line'>  "github.com/hyperledger/fabric/core/chaincode/shim"
</span><span class='line'>  pb "github.com/hyperledger/fabric/protos/peer"
</span><span class='line'>)
</span><span class='line'>
</span><span class='line'>//Chaincode implementation
</span><span class='line'>type SimpleChaincode struct {
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>
</span><span class='line'>// ===================================================================================
</span><span class='line'>// Main
</span><span class='line'>// ===================================================================================
</span><span class='line'>func main() {
</span><span class='line'>  err := shim.Start(new(SimpleChaincode))
</span><span class='line'>  if err != nil {
</span><span class='line'>      fmt.Printf("Error starting Simple chaincode: %s", err)
</span><span class='line'>  }
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>// Init initializes chaincode
</span><span class='line'>// ===========================
</span><span class='line'>func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
</span><span class='line'>  return shim.Success(nil)
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>// Invoke - Our entry point for Invocations
</span><span class='line'>// ========================================
</span><span class='line'>func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
</span><span class='line'>  function, args := stub.GetFunctionAndParameters()
</span><span class='line'>  fmt.Printf("function: %s,args: %s\n", function, args)
</span><span class='line'>
</span><span class='line'>  // Handle different functions
</span><span class='line'>  if function == "save" { //create a new marble
</span><span class='line'>      return t.save(stub, args)
</span><span class='line'>  } else if function == "query" { //find Data based on an ad hoc rich query
</span><span class='line'>      return t.query(stub, args)
</span><span class='line'>  }
</span><span class='line'>
</span><span class='line'>  fmt.Println("invoke did not find func: " + function) //error
</span><span class='line'>  return shim.Error("Received unknown function invocation")
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>// ============================================================
</span><span class='line'>// - create a new data, store into chaincode state
</span><span class='line'>// ============================================================
</span><span class='line'>func (t *SimpleChaincode) save(stub shim.ChaincodeStubInterface, args []string) pb.Response {
</span><span class='line'>  
</span><span class='line'>  if len(args) != 2 {
</span><span class='line'>      return shim.Error("Incorrect number of arguments. Expecting 2")
</span><span class='line'>  }
</span><span class='line'>
</span><span class='line'>  err := stub.PutState(args[0], []byte(args[1]))
</span><span class='line'>  if err != nil {
</span><span class='line'>      return shim.Error(err.Error())
</span><span class='line'>  }
</span><span class='line'>  fmt.Println("- end save business")
</span><span class='line'>  return shim.Success(nil)
</span><span class='line'>  
</span><span class='line'>
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>// ===== Add hoc rich query ========================================================
</span><span class='line'>// query method uses a query string to perform a query for data.
</span><span class='line'>// Query string matching state database syntax is passed in and executed as is.
</span><span class='line'>// Supports ad hoc queries that can be defined at runtime by the client.
</span><span class='line'>// Only available on state databases that support rich query (e.g. CouchDB)
</span><span class='line'>// =========================================================================================
</span><span class='line'>func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
</span><span class='line'>
</span><span class='line'>  //   0
</span><span class='line'>  // "queryString"
</span><span class='line'>  if len(args) &lt; 1 {
</span><span class='line'>      return shim.Error("Incorrect number of arguments. Expecting 1")
</span><span class='line'>  }
</span><span class='line'>
</span><span class='line'>  queryString := args[0]
</span><span class='line'>
</span><span class='line'>  queryResults, err := getQueryResultForQueryString(stub, queryString)
</span><span class='line'>  if err != nil {
</span><span class='line'>      return shim.Error(err.Error())
</span><span class='line'>  }
</span><span class='line'>  return shim.Success(queryResults)
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>// =========================================================================================
</span><span class='line'>// getQueryResultForQueryString executes the passed in query string.
</span><span class='line'>// Result set is built and returned as a byte array containing the JSON results.
</span><span class='line'>// =========================================================================================
</span><span class='line'>func getQueryResultForQueryString(stub shim.ChaincodeStubInterface, queryString string) ([]byte, error) {
</span><span class='line'>
</span><span class='line'>  fmt.Printf("- getQueryResultForQueryString queryString:\n%s\n", queryString)
</span><span class='line'>
</span><span class='line'>  resultsIterator, err := stub.GetQueryResult(queryString)
</span><span class='line'>  if err != nil {
</span><span class='line'>      return nil, err
</span><span class='line'>  }
</span><span class='line'>  defer resultsIterator.Close()
</span><span class='line'>
</span><span class='line'>  // buffer is a JSON array containing QueryRecords
</span><span class='line'>  var buffer bytes.Buffer
</span><span class='line'>  buffer.WriteString("[")
</span><span class='line'>
</span><span class='line'>  bArrayMemberAlreadyWritten := false
</span><span class='line'>  for resultsIterator.HasNext() {
</span><span class='line'>      queryResponse, err := resultsIterator.Next()
</span><span class='line'>      if err != nil {
</span><span class='line'>          return nil, err
</span><span class='line'>      }
</span><span class='line'>      // Add a comma before array members, suppress it for the first array member
</span><span class='line'>      if bArrayMemberAlreadyWritten == true {
</span><span class='line'>          buffer.WriteString(",")
</span><span class='line'>      }
</span><span class='line'>      buffer.WriteString("{\"Key\":")
</span><span class='line'>      buffer.WriteString("\"")
</span><span class='line'>      buffer.WriteString(queryResponse.Key)
</span><span class='line'>      buffer.WriteString("\"")
</span><span class='line'>
</span><span class='line'>      buffer.WriteString(", \"Record\":")
</span><span class='line'>      // Record is a JSON object, so we write as-is
</span><span class='line'>      buffer.WriteString(string(queryResponse.Value))
</span><span class='line'>      buffer.WriteString("}")
</span><span class='line'>      bArrayMemberAlreadyWritten = true
</span><span class='line'>  }
</span><span class='line'>  buffer.WriteString("]")
</span><span class='line'>
</span><span class='line'>  fmt.Printf("- getQueryResultForQueryString queryResult:\n%s\n", buffer.String())
</span><span class='line'>
</span><span class='line'>  return buffer.Bytes(), nil
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<p>save()函数将传上来的数据上链，query()函数通过交易id来查询区块, getQueryResultForQueryString()函数通过交易里的字段来查询区块，目前只支持couchdb查询，leveldb不支持这样查。</p>

<h6>7.4.2、 安装chaincode</h6>

<p>现在我们来安装chaincode</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -s -X POST \
</span><span class='line'>  http://localhost:4000/chaincodes \
</span><span class='line'>  -H "authorization: Bearer &lt;put JSON Web Token here&gt;" \
</span><span class='line'>  -H "content-type: application/json" \
</span><span class='line'>  -d '{
</span><span class='line'>  "peers": ["peer0.org1.xuyao.com","peer1.org1.xuyao.com"],
</span><span class='line'>  "chaincodeName":"mycc",
</span><span class='line'>  "chaincodePath":"github.com/example_cc/go",
</span><span class='line'>  "chaincodeType": "golang",
</span><span class='line'>  "chaincodeVersion":"v0"
</span><span class='line'>}'</span></code></pre></td></tr></table></div></figure>


<p>chaincodeName是智能合约的名字， chaincodePath是智能合约的路径， chaincodeType是编写智能合约的语言，是golang和nodejs两种，chaincodeVersion是智能合约的版本号，值得注意的是如果是升级智能合约的话，需要加上upgrade: true的参数，而且版本号也要向上升级。这是升级的接口，如下:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -s -X POST \
</span><span class='line'>  http://localhost:4000/chaincodes \
</span><span class='line'>  -H "authorization: Bearer &lt;put JSON Web Token here&gt;" \
</span><span class='line'>  -H "content-type: application/json" \
</span><span class='line'>  -d '{
</span><span class='line'>    "peers": ["peer0.org1.xuyao.com","peer1.org1.xuyao.com"],
</span><span class='line'>    "chaincodeName":"mycc",
</span><span class='line'>    "chaincodePath":"github.com/example_cc/go",
</span><span class='line'>    "chaincodeType": "golang",
</span><span class='line'>    "chaincodeVersion":"v1",
</span><span class='line'>    "upgrade": "true"
</span><span class='line'>}'</span></code></pre></td></tr></table></div></figure>


<p>安装成功后，返回如下结果</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{"success":true,"message":"Successfully install chaincode"}</span></code></pre></td></tr></table></div></figure>


<h6>7.4.3、实例化chaincode</h6>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -s -X POST \
</span><span class='line'>  http://localhost:4000/channels/mychannel/chaincodes \
</span><span class='line'>  -H "authorization: Bearer &lt;put JSON Web Token here&gt;" \
</span><span class='line'>  -H "content-type: application/json" \
</span><span class='line'>  -d '{
</span><span class='line'>  "chaincodeName":"mycc",
</span><span class='line'>  "chaincodeVersion":"v0",
</span><span class='line'>  "chaincodeType": "golang",
</span><span class='line'>  "args":["a","100","b","200"]
</span><span class='line'>}'</span></code></pre></td></tr></table></div></figure>


<p>成功返回结果</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{"success":true,"message":"Successfully instantiate chaingcode in organization Org1 to the channel 'mychannel'"}</span></code></pre></td></tr></table></div></figure>


<h6>7.4.4、数据上链</h6>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -s -X POST \
</span><span class='line'>  http://localhost:4000/api/v1/save\
</span><span class='line'>  -H "authorization: Bearer $ORG1_TOKEN" \
</span><span class='line'>  -H "content-type: application/json" \
</span><span class='line'>  -d '{
</span><span class='line'>        "godsCode": "2018092900004",
</span><span class='line'>        "jsonInfo":
</span><span class='line'>          {
</span><span class='line'>          "discern":"1",
</span><span class='line'>          "godsIssuerName":"2",
</span><span class='line'>          "godsIssuerCode":"3",
</span><span class='line'>          "godsTypeName":"4",
</span><span class='line'>          "godsMarketValue":"4",
</span><span class='line'>          "companyName":"5",
</span><span class='line'>          "issuePrice":"6",
</span><span class='line'>          "godsCode":"7",
</span><span class='line'>          "sort":"9",
</span><span class='line'>          "orgCompanyName":"8",
</span><span class='line'>          "orgCode":"",
</span><span class='line'>          "reportId":"",
</span><span class='line'>          "linkTime":"",
</span><span class='line'>          "linkUser":"",
</span><span class='line'>          "linkRole":"",
</span><span class='line'>          "orgSignTime":"",
</span><span class='line'>          "godsSignTime":"",
</span><span class='line'>          "files":[{"fileName":"文件名称.xml","fileHash":"4564613243454546884464"}],
</span><span class='line'>          "attr":[{"key":"name","value":"val"}],
</span><span class='line'>          "companyArea":"所属国家/地区",
</span><span class='line'>          "linkmanPhone":"企业联系电话",
</span><span class='line'>          "linkmanEmail":"企业邮箱",
</span><span class='line'>          "legalPerson":"法人姓名"
</span><span class='line'>        } 
</span><span class='line'>      }'</span></code></pre></td></tr></table></div></figure>


<h6>7.4.5、数据查询</h6>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#通过区块查询
</span><span class='line'>curl -s -X GET \
</span><span class='line'>  "http://localhost:4000/channels/mychannel/blocks/1?peer=peer0.org1.example.com" \
</span><span class='line'>  -H "authorization: Bearer &lt;put JSON Web Token here&gt;" \
</span><span class='line'>  -H "content-type: application/json"
</span><span class='line'>
</span><span class='line'>#通过TransactionID
</span><span class='line'>curl -s -X GET \
</span><span class='line'>http://localhost:4000/channels/mychannel/transactions/&lt;put transaction id here&gt;?peer=peer0.org1.example.com \
</span><span class='line'>  -H "authorization: Bearer &lt;put JSON Web Token here&gt;" \
</span><span class='line'>  -H "content-type: application/json"
</span><span class='line'>
</span><span class='line'>#根据自己的业务ID查询
</span><span class='line'>curl -s -X POST \
</span><span class='line'>    "http://localhost:4000/api/v1/query" \
</span><span class='line'>  -H "authorization: Bearer $ORG1_TOKEN" \
</span><span class='line'>  -H "content-type: application/json" \
</span><span class='line'>  -d '
</span><span class='line'>    {
</span><span class='line'>      "godsCode": "2018092900004"
</span><span class='line'>    }
</span><span class='line'>  '</span></code></pre></td></tr></table></div></figure>


<p>返回结果</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>{"code":200,"message":"操作成功","data":[{"godsCode":"2018092900004","jsonInfo":{"companyArea":"所属国家/地区","companyName":"5","discern":"1","files":[{"fileHash":"4564613243454546884464","fileName":"文件名称.xml"}],"godsCode":"7","godsIssuerCode":"3","godsIssuerName":"2","godsMarketValue":"4","godsSignTime":"","godsTypeName":"4","issuePrice":"6","legalPerson":"法人姓名","linkRole":"","linkTime":"","linkUser":"","linkmanEmail":"企业邮箱","linkmanPhone":"企业联系电话","orgCode":"","orgCompanyName":"8","orgSignTime":"","reportId":"","sort":"9"},"userName":"doc"}]}</span></code></pre></td></tr></table></div></figure>


<h5>未完待续。。。</h5>

<h4>参考资料</h4>

<p>1、<a href="https://github.com/hyperledger/fabric-samples/blob/release-1.3/balance-transfer/README.md">https://github.com/hyperledger/fabric-samples/blob/release-1.3/balance-transfer/README.md</a><br/>
2、<a href="https://jwt.io/">https://jwt.io/</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Fabric多台服务器的部署(三)]]></title>
    <link href="http://xuyao.club/blog/2018/12/29/deployment-of-fabric-multiple-servers-iii/"/>
    <updated>2018-12-29T16:48:58+08:00</updated>
    <id>http://xuyao.club/blog/2018/12/29/deployment-of-fabric-multiple-servers-iii</id>
    <content type="html"><![CDATA[<h4>6、启动Fabric网络</h4>

<p>&emsp;完成上面的工作后，我们已经生成了Fabric所需要的证书和创世纪块等一些必要文件后，现在我们就需要配置docker文件，来启动Fabric网络，之前我们讲过需要启动的一些服务，现在在列一下，服务器一共有4台， 跑4个peer，4个ca, 4个kafka，3个zookeeper, 2个orderer，具体信息如下：<br/>
1、Server1：  peer1、Ca1、 Kafka1、Zookeeper1、Orderer1<br/>
2、Server2：  peer2、Ca2、 Kafka2、Zookeeper2、Orderer2<br/>
3、Server3：   peer3、Ca3、 Kafka3、Zookeeper31<br/>
4、Server4：   peer4、Ca4、 Kafka4<br/>
现在我们需要在各台服务器上启动这些服务，需要说明一下，我们需要先启动zookeeper，再启动kafka，然后启动orderer和peer，这些是有先后顺序的，因为各服务之间有依赖关系，不按顺序启动，最后可能各服务之间的通讯有问题，下面依次来启动这些服务。</p>

<!-- more -->


<h5>6.1、启动Zookeeper集群</h5>

<h6>6.1.1、配置docker-zookeeper.yaml文件，</h6>

<p>&emsp;之前我们假设已经把trace_redwine项目push到远程仓库上，现在我们需要在四台服务器上分别把代码pull下来，进入/artifacts文件夹来配置docker的配置文件。<br/>
&emsp;因为我们前三台服务器都需要docker-zookeeper.yaml文件，所以为了方便配置，我们不防生成三个zookeeper的配置文件，分别用于三台服务器配置上，依次命名如下：docker-zookeeper0.yaml、docker-zookeeper1.yaml、docker-zookeeper2.yaml，下面是docker-zookeeper0.yaml的配置如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>version: '2'
</span><span class='line'>
</span><span class='line'>services:
</span><span class='line'>
</span><span class='line'>  zookeeper0:
</span><span class='line'>    image: hyperledger/fabric-zookeeper
</span><span class='line'>    container_name: zookeeper0
</span><span class='line'>    hostname: zookeeper0
</span><span class='line'>    restart: always
</span><span class='line'>    environment:
</span><span class='line'>      - ZOO_MY_ID=1
</span><span class='line'>      - ZOO_SERVERS=server.1=zookeeper0:2888:3888 server.2=zookeeper1:2888:3888 server.3=zookeeper2:2888:3888
</span><span class='line'>    ports:
</span><span class='line'>      - 2181:2181
</span><span class='line'>      - 2888:2888
</span><span class='line'>      - 3888:3888
</span><span class='line'>    extra_hosts:
</span><span class='line'>      - "kafka0:10.99.22.103"
</span><span class='line'>      - "kafka1:10.99.22.109"
</span><span class='line'>      - "kafka2:10.99.22.101"
</span><span class='line'>      - "kafka3:10.99.22.121"
</span><span class='line'>      - "zookeeper0:0.0.0.0"
</span><span class='line'>      - "zookeeper1:10.99.22.109"
</span><span class='line'>      - "zookeeper2:10.99.22.101"</span></code></pre></td></tr></table></div></figure>


<p>上面配置的参数有几点说明下：<br/>
1、image是指定使用的镜像名称。<br/>
2、container_name是启动容器时的名字。<br/>
3、environment是设置Compose主机上对应的环境变量<br/>
4、ports是暴露端口信息，格式是 宿主端口：容器端口 (HOST:CONTAINER)，<br/>
5、extra_hosts是指定额外的 host 名称映射信息，当节点启动后，服务容器会在 /etc/hosts   文件中添加上面的配置的IP和名称，上面有配置会在/etc/hosts文件中添加如下配置。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>10.99.22.103 kafka0
</span><span class='line'>10.99.22.109 kafka1
</span><span class='line'>10.99.22.101kafka2
</span><span class='line'>10.99.22.121 kafka3
</span><span class='line'>0.0.0.0 zookeeper0
</span><span class='line'>10.99.22.109 zookeeper1
</span><span class='line'>10.99.22.101 zookeeper2</span></code></pre></td></tr></table></div></figure>


<p>6、ZOO_MY_ID是指zookeeper当前服务节点的id， 这个id值是一定需要填的，且唯一的，值的范围在1~255之间。<br/>
10、ZOO_SERVERS是zookeeper集群服务器的列表。</p>

<p>docker-zookeeper1.yaml、docker-zookeeper2.yaml文件配置整体不变，只需要修改一些变量名、环境变量就可以，docker-zookeeper1.yaml的配置文件是:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>version: '2'
</span><span class='line'>
</span><span class='line'>services:
</span><span class='line'>
</span><span class='line'>  zookeeper0:
</span><span class='line'>    image: hyperledger/fabric-zookeeper
</span><span class='line'>    container_name: zookeeper1
</span><span class='line'>    hostname: zookeeper1
</span><span class='line'>    restart: always
</span><span class='line'>    environment:
</span><span class='line'>      - ZOO_MY_ID=2
</span><span class='line'>      - ZOO_SERVERS=server.1=zookeeper0:2888:3888 server.2=zookeeper1:2888:3888 server.3=zookeeper2:2888:3888
</span><span class='line'>    ports:
</span><span class='line'>      - 2181:2181
</span><span class='line'>      - 2888:2888
</span><span class='line'>      - 3888:3888
</span><span class='line'>    extra_hosts:
</span><span class='line'>      - "kafka0:10.99.22.103"
</span><span class='line'>      - "kafka1:10.99.22.109"
</span><span class='line'>      - "kafka2:10.99.22.101"
</span><span class='line'>      - "kafka3:10.99.22.121"
</span><span class='line'>      - "zookeeper0:10.99.22.103"
</span><span class='line'>      - "zookeeper1:10.99.22.109"
</span><span class='line'>      - "zookeeper2:10.99.22.101"</span></code></pre></td></tr></table></div></figure>


<p>需要注意的是我们现在是在多台服务器上，所以每个zookeeper服务的端口可以一样，因为不在一台服务器上，如果我们在本地上跑多个zookeeper，那么这里的端口是需要修改的；docker-zookeeper2.yaml的文件与上面类似，这里不再列出。</p>

<h6>6.1.2、启动Zookeeper</h6>

<p>现在我们分别登录server1,server2,server3三台服务器，来启动这三个zookeeper服务，进入项目的/artifacts文件夹，找到每台服务器对应的docker zookeeper配置文件，使用docker-compose来启动</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#启动zookeeper0
</span><span class='line'>docker-compose -f docker-zookeeper0.yaml up -d</span></code></pre></td></tr></table></div></figure>


<p>启动之后的输出</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>Starting zookeeper0 ... done</span></code></pre></td></tr></table></div></figure>


<p>如果需要看启动的输出日志，则在上面启动命令后不要加 -d, 这样可以直接在启动的时候查看日志输出</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>docker-compose -f docker-zookeeper0.yaml up</span></code></pre></td></tr></table></div></figure>


<p>server2,server3的启动跟上面一样，命令分别如下</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#启动zookeeper1
</span><span class='line'>docker-compose -f docker-zookeeper1.yaml up -d
</span><span class='line'>
</span><span class='line'>#启动zookeeper2
</span><span class='line'>docker-compose -f docker-zookeeper2.yaml up -d</span></code></pre></td></tr></table></div></figure>


<p>启动成功后，可以使用docker命令查看运行状态</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>docker ps -a</span></code></pre></td></tr></table></div></figure>


<p>可以看到zookeeper0是正在运行的状态</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>CONTAINER ID        IMAGE                                                                                                          COMMAND                  CREATED             STATUS              PORTS                                                                                                                                               NAMES
</span><span class='line'>980c8bb7190d        hyperledger/fabric-zookeeper                                                                                   "/docker-entrypoint.…"   7 days ago          Up 7 days           0.0.0.0:2181-&gt;2181/tcp, 0.0.0.0:2888-&gt;2888/tcp, 0.0.0.0:3888-&gt;3888/tcp, 0.0.0.0:32773-&gt;2181/tcp, 0.0.0.0:32772-&gt;2888/tcp, 0.0.0.0:32771-&gt;3888/tcp   zookeeper0</span></code></pre></td></tr></table></div></figure>


<h5>6.2、启动Kafka集群</h5>

<h6>6.2.1、配置docker-kafka.yaml文件</h6>

<p>因为我们有4个kafka服务，所以我们可以生成4个配置文件来启动这4个服务，配置文件分别如下docker-kafka0.yaml、docker-kafka1.yaml、docker-kafka2.yaml、docker-kafka3.yaml。
docker-kafka0.yaml的配置文件如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>version: '2'
</span><span class='line'>
</span><span class='line'>services:
</span><span class='line'>
</span><span class='line'>  kafka0:
</span><span class='line'>    image: hyperledger/fabric-kafka
</span><span class='line'>    container_name: kafka0
</span><span class='line'>    hostname: kafka0
</span><span class='line'>    restart: always
</span><span class='line'>    environment:
</span><span class='line'>      - KAFKA_BROKER_ID=0
</span><span class='line'>      - KAFKA_MIN_INSYNC_REPLICAS=2
</span><span class='line'>      - KAFKA_DEFAULT_REPLICATION_FACTOR=3
</span><span class='line'>      - KAFKA_ZOOKEEPER_CONNECT=zookeeper0:2181,zookeeper1:2181,zookeeper2:2181
</span><span class='line'>      - KAFKA_MESSAGE_MAX_BYTES=103809024 # 99 * 1024 * 1024 B
</span><span class='line'>      - KAFKA_REPLICA_FETCH_MAX_BYTES=103809024 # 99 * 1024 * 1024 B
</span><span class='line'>      - KAFKA_UNCLEAN_LEADER_ELECTION_ENABLE=false
</span><span class='line'>      - KAFKA_LOG_RETENTION_MS=-1
</span><span class='line'>      - KAFKA_LOG.DIRS=/var/hyperledger/production/kafka0/kafka-logs
</span><span class='line'>    volumes:
</span><span class='line'>       - ../mount/kafka0/var/hyperledger/production:/var/hyperledger/production/kafka0/kafka-logs
</span><span class='line'>    ports:
</span><span class='line'>      - 9092:9092
</span><span class='line'>    extra_hosts:
</span><span class='line'>      - "kafka0:10.99.22.103"
</span><span class='line'>      - "kafka1:10.99.22.109"
</span><span class='line'>      - "kafka2:10.99.22.101"
</span><span class='line'>      - "kafka3:10.99.22.121"
</span><span class='line'>      - "zookeeper0:10.99.22.103"
</span><span class='line'>      - "zookeeper1:10.99.22.109"
</span><span class='line'>      - "zookeeper2:10.99.22.101"</span></code></pre></td></tr></table></div></figure>


<p>说明几点：<br/>
1、KAFKA_BROKER_ID是BROKER的唯一标识，不可重复，且非负整数。  <br/>
2、KAFKA_ZOOKEEPER_CONNECT是指向zookeeper节点的集合。<br/>
3、volumes是docker里数据卷所挂载路径设置，可以设置宿主机路径 （HOST:CONTAINER） 或加上访问模式（HOST:CONTAINER:ro）。</p>

<p>docker-kafka1.yaml、docker-kafka2.yaml、docker-kafka3.yaml的配置基本与上面的一样，只要修改一下KAFKA_BROKER_ID参数就可以，如docker-kafka1.yaml的配置文件是：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>version: '2'
</span><span class='line'>
</span><span class='line'>services:
</span><span class='line'>
</span><span class='line'>  kafka1:
</span><span class='line'>    image: hyperledger/fabric-kafka
</span><span class='line'>    container_name: kafka1
</span><span class='line'>    hostname: kafka1
</span><span class='line'>    restart: always
</span><span class='line'>    environment:
</span><span class='line'>      - KAFKA_BROKER_ID=1
</span><span class='line'>      - KAFKA_MIN_INSYNC_REPLICAS=2
</span><span class='line'>      - KAFKA_DEFAULT_REPLICATION_FACTOR=3
</span><span class='line'>      - KAFKA_ZOOKEEPER_CONNECT=zookeeper0:2181,zookeeper1:2181,zookeeper2:2181
</span><span class='line'>      - KAFKA_MESSAGE_MAX_BYTES=103809024 # 99 * 1024 * 1024 B
</span><span class='line'>      - KAFKA_REPLICA_FETCH_MAX_BYTES=103809024 # 99 * 1024 * 1024 B
</span><span class='line'>      - KAFKA_UNCLEAN_LEADER_ELECTION_ENABLE=false
</span><span class='line'>      - KAFKA_LOG_RETENTION_MS=-1
</span><span class='line'>      - KAFKA_LOG.DIRS=/var/hyperledger/production/kafka0/kafka-logs
</span><span class='line'>    volumes:
</span><span class='line'>       - ../mount/kafka0/var/hyperledger/production:/var/hyperledger/production/kafka0/kafka-logs
</span><span class='line'>    ports:
</span><span class='line'>      - 9092:9092
</span><span class='line'>    extra_hosts:
</span><span class='line'>      - "kafka0:10.99.22.103"
</span><span class='line'>      - "kafka1:10.99.22.109"
</span><span class='line'>      - "kafka2:10.99.22.101"
</span><span class='line'>      - "kafka3:10.99.22.121"
</span><span class='line'>      - "zookeeper0:10.99.22.103"
</span><span class='line'>      - "zookeeper1:10.99.22.109"
</span><span class='line'>      - "zookeeper2:10.99.22.101"</span></code></pre></td></tr></table></div></figure>


<p>docker-kafka2.yaml、docker-kafka3.yaml按照上面改就行，这里不一一列出。</p>

<h6>6.2.2、启动Kafka集群</h6>

<p>&emsp;现在我们分别登录4台服务器上，进入/artifacts项目路径下，找到刚才我们生成的那些docker-kafka.yaml的配置文件，使用命令依次启动各服务器上的kafka服务</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#启动kafka0
</span><span class='line'>docker-compose -f docker-kafka0.yaml up -d</span></code></pre></td></tr></table></div></figure>


<p>server1，server2，server3启动方法和上面一样</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#启动kafka1
</span><span class='line'>docker-compose -f docker-kafka1.yaml up -d
</span><span class='line'>
</span><span class='line'>#启动kafka2
</span><span class='line'>docker-compose -f docker-kafka2.yaml up -d
</span><span class='line'>
</span><span class='line'>#启动kafka3
</span><span class='line'>docker-compose -f docker-kafka3.yaml up -d</span></code></pre></td></tr></table></div></figure>


<p>最后可以在各服务器上使用docker 命令查看是否启动成功</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>docker ps -a
</span><span class='line'>
</span><span class='line'>CONTAINER ID        IMAGE                                                                                                          COMMAND                  CREATED             STATUS              PORTS                                                                                                                                               NAMES
</span><span class='line'>4bde08ae4413        hyperledger/fabric-kafka                                                                                       "/docker-entrypoint.…"   7 days ago          Up 7 days           0.0.0.0:9092-&gt;9092/tcp, 9093/tcp, 0.0.0.0:32774-&gt;9092/tcp                                                                                           kafka0</span></code></pre></td></tr></table></div></figure>


<h5>6.3、启动Orderer集群</h5>

<h6>6.3.1、配置docker-orderer.yaml文件</h6>

<p> &emsp;orderer服务我们只有server1,server2上有，所以我们只需要两个启动配置文件就行，命名如下docker-orderer0.yaml,docker-orderer1.yaml，
其中docker-orderer0.yaml的配置文件如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># Copyright IBM Corp. All Rights Reserved.
</span><span class='line'>#
</span><span class='line'># SPDX-License-Identifier: Apache-2.0
</span><span class='line'>#
</span><span class='line'>
</span><span class='line'>version: '2'
</span><span class='line'>
</span><span class='line'>services:
</span><span class='line'>
</span><span class='line'>  orderer0.xuyao.com:
</span><span class='line'>      container_name: orderer0.xuyao.com
</span><span class='line'>      image: hyperledger/fabric-orderer:latest
</span><span class='line'>      environment:
</span><span class='line'>        - ORDERER_GENERAL_LOGLEVEL=debug
</span><span class='line'>        - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
</span><span class='line'>        - ORDERER_GENERAL_GENESISMETHOD=file
</span><span class='line'>        - ORDERER_GENERAL_GENESISFILE=/etc/hyperledger/configtx/genesis.block
</span><span class='line'>        - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
</span><span class='line'>        - ORDERER_GENERAL_LOCALMSPDIR=/etc/hyperledger/crypto/orderer/msp
</span><span class='line'>        - ORDERER_GENERAL_TLS_ENABLED=true
</span><span class='line'>        - GODEBUG=netdns=go
</span><span class='line'>        - ORDERER_GENERAL_TLS_PRIVATEKEY=/etc/hyperledger/crypto/orderer/tls/server.key
</span><span class='line'>        - ORDERER_GENERAL_TLS_CERTIFICATE=/etc/hyperledger/crypto/orderer/tls/server.crt
</span><span class='line'>        - ORDERER_GENERAL_TLS_ROOTCAS=[/etc/hyperledger/crypto/orderer/tls/ca.crt, /etc/hyperledger/crypto/peerOrg1/tls/ca.crt, /etc/hyperledger/crypto/peerOrg2/tls/ca.crt, /etc/hyperledger/crypto/peerOrg3/tls/ca.crt, /etc/hyperledger/crypto/peerOrg4/tls/ca.crt]
</span><span class='line'>        - ORDERER_KAFKA_RETRY_SHORTINTERVAL=1s
</span><span class='line'>        - ORDERER_KAFKA_RETRY_SHORTTOTAL=30s
</span><span class='line'>        - ORDERER_KAFKA_VERBOSE=true
</span><span class='line'>      working_dir: /opt/gopath/src/github.com/hyperledger/fabric/orderers
</span><span class='line'>      command: orderer
</span><span class='line'>      ports:
</span><span class='line'>        - 7050:7050
</span><span class='line'>      volumes:
</span><span class='line'>        - ./channel:/etc/hyperledger/configtx
</span><span class='line'>        - ./channel/crypto-config/ordererOrganizations/xuyao.com/orderers/orderer0.xuyao.com/:/etc/hyperledger/crypto/orderer
</span><span class='line'>        - ./channel/crypto-config/peerOrganizations/org1.xuyao.com/peers/peer0.org1.xuyao.com/:/etc/hyperledger/crypto/peerOrg1
</span><span class='line'>        - ./channel/crypto-config/peerOrganizations/org2.xuyao.com/peers/peer0.org2.xuyao.com/:/etc/hyperledger/crypto/peerOrg2
</span><span class='line'>        - ./channel/crypto-config/peerOrganizations/org3.xuyao.com/peers/peer0.org3.xuyao.com/:/etc/hyperledger/crypto/peerOrg3
</span><span class='line'>        - ./channel/crypto-config/peerOrganizations/org4.xuyao.com/peers/peer0.org4.xuyao.com/:/etc/hyperledger/crypto/peerOrg4
</span><span class='line'>        - ../mount/orderer1/var/hyperledger/production:/var/hyperledger/production
</span><span class='line'>      extra_hosts:
</span><span class='line'>        - "kafka0:10.99.22.103"
</span><span class='line'>        - "kafka1:10.99.22.109"
</span><span class='line'>        - "kafka2:10.99.22.101"
</span><span class='line'>        - "kafka3:10.99.22.121"</span></code></pre></td></tr></table></div></figure>


<p>说明：<br/>
1、ORDERER_GENERAL_TLS_PRIVATEKEY是为服务器证书设置私钥文件的位置。<br/>
2、ORDERER_GENERAL_TLS_CERTIFICATE是为TLS设置服务器证书的位置。<br/>
3、ORDERER_GENERAL_TLS_ROOTCAS是为TLS设置根证书的位置。</p>

<p>docker-orderer1.yaml的配置文件基本与docker-orderer1.yaml差不多，如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>
</span><span class='line'>version: '2'
</span><span class='line'>
</span><span class='line'>services:
</span><span class='line'>
</span><span class='line'>  orderer1.xuyao.com:
</span><span class='line'>      container_name: orderer1.xuyao.com
</span><span class='line'>      image: hyperledger/fabric-orderer:latest
</span><span class='line'>      environment:
</span><span class='line'>        - ORDERER_GENERAL_LOGLEVEL=debug
</span><span class='line'>        - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
</span><span class='line'>        - ORDERER_GENERAL_GENESISMETHOD=file
</span><span class='line'>        - ORDERER_GENERAL_GENESISFILE=/etc/hyperledger/configtx/genesis.block
</span><span class='line'>        - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
</span><span class='line'>        - ORDERER_GENERAL_LOCALMSPDIR=/etc/hyperledger/crypto/orderer/msp
</span><span class='line'>        - ORDERER_GENERAL_TLS_ENABLED=true
</span><span class='line'>        - GODEBUG=netdns=go
</span><span class='line'>        - ORDERER_GENERAL_TLS_PRIVATEKEY=/etc/hyperledger/crypto/orderer/tls/server.key
</span><span class='line'>        - ORDERER_GENERAL_TLS_CERTIFICATE=/etc/hyperledger/crypto/orderer/tls/server.crt
</span><span class='line'>        - ORDERER_GENERAL_TLS_ROOTCAS=[/etc/hyperledger/crypto/orderer/tls/ca.crt, /etc/hyperledger/crypto/peerOrg1/tls/ca.crt, /etc/hyperledger/crypto/peerOrg2/tls/ca.crt, /etc/hyperledger/crypto/peerOrg3/tls/ca.crt, /etc/hyperledger/crypto/peerOrg4/tls/ca.crt]
</span><span class='line'>        - ORDERER_KAFKA_RETRY_SHORTINTERVAL=1s
</span><span class='line'>        - ORDERER_KAFKA_RETRY_SHORTTOTAL=30s
</span><span class='line'>        - ORDERER_KAFKA_VERBOSE=true
</span><span class='line'>      working_dir: /opt/gopath/src/github.com/hyperledger/fabric/orderers
</span><span class='line'>      command: orderer
</span><span class='line'>      ports:
</span><span class='line'>        - 7050:7050
</span><span class='line'>      volumes:
</span><span class='line'>        - ./channel:/etc/hyperledger/configtx
</span><span class='line'>        - ./channel/crypto-config/ordererOrganizations/xuyao.com/orderers/orderer1.xuyao.com/:/etc/hyperledger/crypto/orderer
</span><span class='line'>        - ./channel/crypto-config/peerOrganizations/org1.xuyao.com/peers/peer0.org1.xuyao.com/:/etc/hyperledger/crypto/peerOrg1
</span><span class='line'>        - ./channel/crypto-config/peerOrganizations/org2.xuyao.com/peers/peer0.org2.xuyao.com/:/etc/hyperledger/crypto/peerOrg2
</span><span class='line'>        - ./channel/crypto-config/peerOrganizations/org3.xuyao.com/peers/peer0.org3.xuyao.com/:/etc/hyperledger/crypto/peerOrg3
</span><span class='line'>        - ./channel/crypto-config/peerOrganizations/org4.xuyao.com/peers/peer0.org4.xuyao.com/:/etc/hyperledger/crypto/peerOrg4
</span><span class='line'>        - ../mount/orderer1/var/hyperledger/production:/var/hyperledger/production
</span><span class='line'>      extra_hosts:
</span><span class='line'>        - "kafka0:10.99.22.103"
</span><span class='line'>        - "kafka1:10.99.22.109"
</span><span class='line'>        - "kafka2:10.99.22.101"
</span><span class='line'>        - "kafka3:10.99.22.121"</span></code></pre></td></tr></table></div></figure>


<h6>6.3.2、启动Orderer集群</h6>

<p> &emsp;我们分别在server1,server2上启动orderer，登录各服务器，进入各自的配置文件目录下，使用如下命令启动orderer</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#启动orderer0
</span><span class='line'>docker-compose -f docker-orderer0.yaml up -d
</span><span class='line'>
</span><span class='line'>#启动orderer1
</span><span class='line'>docker-compose -f docker-orderer1.yaml up -d</span></code></pre></td></tr></table></div></figure>


<p>使用docker命令查看orderer状态</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>docker ps -a
</span><span class='line'>
</span><span class='line'>CONTAINER ID        IMAGE                                                                                                          COMMAND                  CREATED             STATUS              PORTS                                                                                                                                               NAMES
</span><span class='line'>806f354f4e62        hyperledger/fabric-orderer:latest                                                                              "orderer"                7 days ago          Up 7 days           0.0.0.0:7050-&gt;7050/tcp                                                                                                                              orderer1.mbasechain.com</span></code></pre></td></tr></table></div></figure>


<h5>6.4、启动Peer集群</h5>

<h6>6.4.1、配置docker-peer.yaml文件</h6>

<p> &emsp;peer节点在四台服务器上都有，所以我们需要生成4个配置文件分别叫docker-peer0.yaml, docker-peer1yaml,docker-peer2.yaml,docker-peer3.yaml，下面对docker-peer0.yaml作配置</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>version: '2'
</span><span class='line'>
</span><span class='line'>services:
</span><span class='line'>
</span><span class='line'>  couchdb:
</span><span class='line'>    container_name: couchdb
</span><span class='line'>    image: hyperledger/fabric-couchdb:latest
</span><span class='line'>    ports:
</span><span class='line'>      - "5984:5984"
</span><span class='line'>
</span><span class='line'>  peer0.org1.xuyao.com:
</span><span class='line'>    container_name: peer0.org1.xuyao.com
</span><span class='line'>    image: hyperledger/fabric-peer:latest
</span><span class='line'>    environment:
</span><span class='line'>      - CORE_PEER_ID=peer0.org1.xuyao.com
</span><span class='line'>      - CORE_PEER_LOCALMSPID=Org1MSP
</span><span class='line'>      - CORE_PEER_ADDRESS=peer0.org1.xuyao.com:7051
</span><span class='line'>      - CORE_LEDGER_STATE_STATEDATABASE=CouchDB
</span><span class='line'>      - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
</span><span class='line'>      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
</span><span class='line'>      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=artifacts_default
</span><span class='line'>      - CORE_LOGGING_LEVEL=debug
</span><span class='line'>      - CORE_PEER_GOSSIP_USELEADERELECTION=true
</span><span class='line'>      - CORE_PEER_GOSSIP_ORGLEADER=false
</span><span class='line'>      - GODEBUG=netdns=go
</span><span class='line'>      # The following setting skips the gossip handshake since we are
</span><span class='line'>      # are not doing mutual TLS
</span><span class='line'>      - CORE_PEER_GOSSIP_SKIPHANDSHAKE=true
</span><span class='line'>      - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/crypto/peer/msp
</span><span class='line'>      - CORE_PEER_TLS_ENABLED=true
</span><span class='line'>      - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/crypto/peer/tls/server.key
</span><span class='line'>      - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/crypto/peer/tls/server.crt
</span><span class='line'>      - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/crypto/peer/tls/ca.crt
</span><span class='line'>    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
</span><span class='line'>    command: peer node start
</span><span class='line'>    ports:
</span><span class='line'>      - 7051:7051
</span><span class='line'>      - 7053:7053
</span><span class='line'>    volumes:
</span><span class='line'>        - /var/run/:/host/var/run/
</span><span class='line'>        - ./channel/crypto-config/peerOrganizations/org1.mbasechain.com/peers/peer0.org1.xuyao.com/:/etc/hyperledger/crypto/peer
</span><span class='line'>        - ../mount/peer0.org1.xuyao.com/var/hyperledger/production:/var/hyperledger/production
</span><span class='line'>    depends_on:
</span><span class='line'>        - couchdb
</span><span class='line'>    extra_hosts:
</span><span class='line'>      - "orderer0.mbasechain.com:10.99.22.103"
</span><span class='line'>      - "orderer1.mbasechain.com:10.99.22.109"</span></code></pre></td></tr></table></div></figure>


<p>说明：<br/>
1、CORE_PEER_ID是当前peer节点的id。<br/>
2、CORE_PEER_LOCALMSPID是当前peer节点服务的成员服务提供者id。<br/>
3、CORE_PEER_ADDRESS是当前peer节点在Fabric网络中的地址。</p>

<p>docker-peer1.yaml,docker-peer2.yaml,docker-peer3.yaml文件配置和docker-peer0.yaml基本一样，修改一下主要的参数就行，这里不一一列出</p>

<h6>6.4.2、启动Peer集群</h6>

<p>&emsp; 我们4台服务器上都有peer节点，所以我们现在分别登录这4台服务器，把刚才的配置文件更新好后，就可以依次启动这4个peer节点了。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#启动peer0
</span><span class='line'>docker-compose -f docker-peer0.yaml up -d 
</span><span class='line'>
</span><span class='line'>#启动peer1
</span><span class='line'>docker-compose -f docker-peer1.yaml up -d 
</span><span class='line'>
</span><span class='line'>#启动peer2
</span><span class='line'>docker-compose -f docker-peer2.yaml up -d 
</span><span class='line'>
</span><span class='line'>#启动peer3
</span><span class='line'>docker-compose -f docker-peer3.yaml up -d </span></code></pre></td></tr></table></div></figure>


<p>启动成功后，我们再通过docker命令查看peer运行状态</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>docker ps -a
</span><span class='line'>
</span><span class='line'>#运行状态
</span><span class='line'>CONTAINER ID        IMAGE                                                                                                          COMMAND                  CREATED             STATUS              PORTS                                                                                                                                               NAMES
</span><span class='line'>7a2582136861        hyperledger/fabric-peer:latest                                                                                 "peer node start"        7 days ago          Up 7 days           0.0.0.0:7051-&gt;7051/tcp, 0.0.0.0:7053-&gt;7053/tcp                                                                                                      peer0.org1.mbasechain.com</span></code></pre></td></tr></table></div></figure>


<h5>6.5、启动Ca集群</h5>

<h6>6.5.1、配置docker-ca-org.yaml文件</h6>

<p>&emsp; ca在4台服务器也都有，所以我们需要生成4个文件来分别配置4个ca，现生成4个docker配置文件为 docker-ca-org0.yaml,docker-ca-org1.yaml,docker-ca-org2.yaml,docker-ca-org3.yaml,配置如下</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>version: '2'
</span><span class='line'>
</span><span class='line'>services:
</span><span class='line'>
</span><span class='line'>  ca.org1.xuyao.com:
</span><span class='line'>    container_name: ca
</span><span class='line'>    image: hyperledger/fabric-ca:latest
</span><span class='line'>    environment:
</span><span class='line'>      - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server
</span><span class='line'>      - FABRIC_CA_SERVER_CA_NAME=ca.org1.xuyao.com
</span><span class='line'>      - FABRIC_CA_SERVER_CA_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.ORG_NAME-cert.pem
</span><span class='line'>      - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/9af18a6c9dd8f34db73a70c1d066e6948216db534af9e4f89029158089d56cf1_sk
</span><span class='line'>      - FABRIC_CA_SERVER_TLS_ENABLED=true
</span><span class='line'>      - FABRIC_CA_SERVER_TLS_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org1.xuyao.com-cert.pem
</span><span class='line'>      - FABRIC_CA_SERVER_TLS_KEYFILE=/etc/hyperledger/fabric-ca-server-config/9af18a6c9dd8f34db73a70c1d066e6948216db534af9e4f89029158089d56cf1_sk
</span><span class='line'>    ports:
</span><span class='line'>      - "7054:7054"
</span><span class='line'>    command: sh -c 'fabric-ca-server start -b admin:adminpw -d'
</span><span class='line'>    volumes:
</span><span class='line'>      - ./channel/crypto-config/peerOrganizations/org1.xuyao.com/ca/:/etc/hyperledger/fabric-ca-server-config
</span><span class='line'>    container_name: ca.org1.xuyao.com</span></code></pre></td></tr></table></div></figure>


<p>其它三个配置文件根据ca的名字不同，改下一些参数名字就行，将这些文件配置好后，提交到远程仓库</p>

<h6>6.5.2、启动Ca集群</h6>

<p>&emsp; 现在我们分别登录4台服务器，把刚才修改的配置文件下来，准备启动ca服务，命令如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#启动ca-org0
</span><span class='line'>docker-compose  -f docker-ca-org0.yaml up -d
</span><span class='line'>
</span><span class='line'>#启动ca-org1
</span><span class='line'>docker-compose  -f docker-ca-org1.yaml up -d
</span><span class='line'>
</span><span class='line'>#启动ca-org2
</span><span class='line'>docker-compose  -f docker-ca-org2.yaml up -d
</span><span class='line'>
</span><span class='line'>#启动ca-org3
</span><span class='line'>docker-compose  -f docker-ca-org3.yaml up -d</span></code></pre></td></tr></table></div></figure>


<p>至此整个Fabric网络所需的节点都已经启动完了，我们可以使用命令来查看各个服务器所有正在运行的服务</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#查看所以服务
</span><span class='line'>docker ps -a
</span><span class='line'>
</span><span class='line'>CONTAINER ID        IMAGE                                                                                                          COMMAND                  CREATED             STATUS              PORTS                                                                                                                                               NAMES
</span><span class='line'>96529e278e54        hyperledger/fabric-ca:latest                                                                                   "sh -c 'fabric-ca-se…"   7 days ago          Up 7 days           0.0.0.0:7054-&gt;7054/tcp                                                                                                                              ca.org1.mbasechain.com
</span><span class='line'>7a2582136861        hyperledger/fabric-peer:latest                                                                                 "peer node start"        7 days ago          Up 7 days           0.0.0.0:7051-&gt;7051/tcp, 0.0.0.0:7053-&gt;7053/tcp                                                                                                      peer0.org1.mbasechain.com
</span><span class='line'>49b5ee98950b        hyperledger/fabric-couchdb:latest                                                                              "tini -- /docker-ent…"   7 days ago          Up 7 days           4369/tcp, 9100/tcp, 0.0.0.0:5984-&gt;5984/tcp                                                                                                          couchdb
</span><span class='line'>806f354f4e62        hyperledger/fabric-orderer:latest                                                                              "orderer"                7 days ago          Up 7 days           0.0.0.0:7050-&gt;7050/tcp                                                                                                                              orderer1.mbasechain.com
</span><span class='line'>4bde08ae4413        hyperledger/fabric-kafka                                                                                       "/docker-entrypoint.…"   7 days ago          Up 7 days           0.0.0.0:9092-&gt;9092/tcp, 9093/tcp, 0.0.0.0:32774-&gt;9092/tcp                                                                                           kafka0
</span><span class='line'>980c8bb7190d        hyperledger/fabric-zookeeper                                                                                   "/docker-entrypoint.…"   7 days ago          Up 7 days           0.0.0.0:2181-&gt;2181/tcp, 0.0.0.0:2888-&gt;2888/tcp, 0.0.0.0:3888-&gt;3888/tcp, 0.0.0.0:32773-&gt;2181/tcp, 0.0.0.0:32772-&gt;2888/tcp, 0.0.0.0:32771-&gt;3888/tcp   zookeeper0</span></code></pre></td></tr></table></div></figure>


<p>可以看到docker里运行了zookeeper,kafka,orderer, peer, ca, couchdb6个服务，到这里整个Fabric启动工作就全部做好了，下篇文章将写安装channel和chaincode</p>

<h5>未完待续。。。</h5>

<h4>参考资料</h4>

<p>【HyperLedger Fabric 开发实战】
<a href="https://www.jianshu.com/p/040a09e2098e">https://www.jianshu.com/p/040a09e2098e</a><br/>
<a href="https://yeasy.gitbooks.io/docker_practice/data_management/volume.html">https://yeasy.gitbooks.io/docker_practice/data_management/volume.html</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Fabric多台服务器的部署(二)]]></title>
    <link href="http://xuyao.club/blog/2018/12/14/deployment-of-fabric-multiple-servers-ii/"/>
    <updated>2018-12-14T14:27:46+08:00</updated>
    <id>http://xuyao.club/blog/2018/12/14/deployment-of-fabric-multiple-servers-ii</id>
    <content type="html"><![CDATA[<h3>3、下载Fabric镜像</h3>

<h5>3.1.1 下载Fabric 源码</h5>

<p> 1、在后面的例子中，有些地方需要用到源码中提到的工具来编译和生成证书等，这里需要下载一下Fabric的源码，在本地下载Fabric官方提供的源码</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>git clone git@github.com:hyperledger/fabric.git</span></code></pre></td></tr></table></div></figure>


<p>需要注意的时候，需要把下载好的源码放在$GOPATH里，这个环境变量是最初安装GO的设置的，如</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>echo $GOPATH
</span><span class='line'>/Users/xuyao/go</span></code></pre></td></tr></table></div></figure>


<p>那么fabric的源码地址路径应该是</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>/Users/xuyao/go/src/github.com/hyperledger/fabric/</span></code></pre></td></tr></table></div></figure>


<!-- more -->


<h5>3.1.2 下载Fabric镜像</h5>

<p> &emsp;如果你看过Fabric官方的快速入门文档<a href="https://hyperledgercn.github.io/hyperledgerDocs/getting_started/">https://hyperledgercn.github.io/hyperledgerDocs/getting_started/</a>，应该会对Fabric的镜像文件有个了解，在fabric/examples/e2e_cli文件夹下有个download-dockerimages.sh的脚本文件，他会帮你一键下载所需的镜像文件。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># 使脚本可执行
</span><span class='line'>chmod +x download-dockerimages.sh
</span><span class='line'># 执行脚本
</span><span class='line'>./download-dockerimages.sh</span></code></pre></td></tr></table></div></figure>


<p>当然也可以使用下面命令下载镜像(需要翻墙)</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -sSL http://bit.ly/2ysbOFE | bash -s 1.2.0 
</span><span class='line'>#此处是下载fabric-samples，如果想快速使用byfn可以参考此脚本，后面1.2.0是对应的版本号</span></code></pre></td></tr></table></div></figure>


<p>也可以根据自己项目需求下载不同的版本</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -sSL http://bit.ly/2ysbOFE | bash -s &lt;fabric&gt; &lt;fabric-ca&gt; &lt;thirdparth&gt;
</span><span class='line'>curl -sSL http://bit.ly/2ysbOFE | bash -s 1.2.0 1.2.0 0.4.10
</span><span class='line'>#后面三个参数分别代表Fabric, Fabric-ca和第三方平台镜像版本号</span></code></pre></td></tr></table></div></figure>


<p>无法翻墙，可以用下面命令</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh | bash -s 1.2.0 1.2.0 0.4.10</span></code></pre></td></tr></table></div></figure>


<p>下载完成后使用docker images可以看到下载的镜像文件</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>docker images #查看所以镜像文件
</span><span class='line'>hyperledger/fabric-ca          latest               35311d8617b4        7 days ago          240 MB
</span><span class='line'>hyperledger/fabric-ca          x86_64-1.0.0-alpha   35311d8617b4        7 days ago          240 MB
</span><span class='line'>hyperledger/fabric-couchdb     latest               f3ce31e25872        7 days ago          1.51 GB
</span><span class='line'>hyperledger/fabric-couchdb     x86_64-1.0.0-alpha   f3ce31e25872        7 days ago          1.51 GB
</span><span class='line'>hyperledger/fabric-kafka       latest               589dad0b93fc        7 days ago          1.3 GB
</span><span class='line'>hyperledger/fabric-kafka       x86_64-1.0.0-alpha   589dad0b93fc        7 days ago          1.3 GB
</span><span class='line'>hyperledger/fabric-zookeeper   latest               9a51f5be29c1        7 days ago          1.31 GB
</span><span class='line'>hyperledger/fabric-zookeeper   x86_64-1.0.0-alpha   9a51f5be29c1        7 days ago          1.31 GB
</span><span class='line'>hyperledger/fabric-orderer     latest               5685fd77ab7c        7 days ago          182 MB
</span><span class='line'>hyperledger/fabric-orderer     x86_64-1.0.0-alpha   5685fd77ab7c        7 days ago          182 MB
</span><span class='line'>hyperledger/fabric-peer        latest               784c5d41ac1d        7 days ago          184 MB
</span><span class='line'>hyperledger/fabric-peer        x86_64-1.0.0-alpha   784c5d41ac1d        7 days ago          184 MB
</span><span class='line'>hyperledger/fabric-javaenv     latest               a08f85d8f0a9        7 days ago          1.42 GB
</span><span class='line'>hyperledger/fabric-javaenv     x86_64-1.0.0-alpha   a08f85d8f0a9        7 days ago          1.42 GB
</span><span class='line'>hyperledger/fabric-ccenv       latest               91792014b61f        7 days ago          1.29 GB
</span><span class='line'>hyperledger/fabric-ccenv       x86_64-1.0.0-alpha   91792014b61f        7 days ago          1.29 GB</span></code></pre></td></tr></table></div></figure>


<h5>3.1.3 常用的Docker 命令</h5>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#停止正在运行的所有网络
</span><span class='line'>docker stop -f $(docker ps -aq)
</span><span class='line'>
</span><span class='line'>#删除正在运行的所有网络
</span><span class='line'>docker rm -f $(docker ps -aq)
</span><span class='line'>
</span><span class='line'>#删除某个镜像
</span><span class='line'>docker rmi &lt;IMAGE ID&gt;
</span><span class='line'>
</span><span class='line'>#查看某个容器的日志
</span><span class='line'>docker logs -f  &lt; container-id &gt;
</span><span class='line'>
</span><span class='line'>#进入某个容器内部
</span><span class='line'>docker exec -it &lt; container-id &gt; bash
</span><span class='line'>
</span><span class='line'>#查看docker 运行状态
</span><span class='line'>service docker status
</span><span class='line'>
</span><span class='line'># 启动/关闭docker
</span><span class='line'>sudo service docker start|stop</span></code></pre></td></tr></table></div></figure>


<h4>4、下载 Fabric-sample 源码</h4>

<p>1、fabric-sample里有很多快速启动fabric的例子，官方文档给了一个快速启动first-network的例子 <a href="https://hyperledgercn.github.io/hyperledgerDocs/build_network_zh/">https://hyperledgercn.github.io/hyperledgerDocs/build_network_zh/</a>，在first-network里面，每个组织持有2个peer节点，以及一个“solo”排序服务，这里一个比较简单的fabric网络，如果只是想跑一下fabric网络，试下手感的话，可以按照官方的文档来跑一篇。<br/>
 &emsp; 这里我们用的是官网提供的另一个例子，balance-transfer，它是一个集成了nodejs sdk的一个node.js的简单例子。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#下载fabric-sample
</span><span class='line'>git clone git@github.com:hyperledger/fabric-samples.git</span></code></pre></td></tr></table></div></figure>


<p> 2、后期我们的项目都是用nodejs来做的，所以很多基础的东西可以复用balance-transfer里的，现在我们可以自己建了项目仓库叫trace_redwine，把fabric-samples/balance-transfer/里的文件全部copy到我们的trace_redwine里,删除一些不必要的文件，这里一个自己的fabric项目雏形就出来了。</p>

<h4>5、修改配置脚本</h4>

<h5>5.1.1 修改crypto-config.yaml文件</h5>

<p> &emsp; crypto-config.yaml文件是配置节点信息的，你可以配置你的orderer,peer数量，以及域名的设置，主要配置的是OrdererOrgs和PeerOrgs<br/>
OrdererOrgs的配置</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>OrdererOrgs:
</span><span class='line'>  - Name: Orderer
</span><span class='line'>    Domain: xuyao.com
</span><span class='line'>    Specs:
</span><span class='line'>      - Hostname: orderer1
</span><span class='line'>      - Hostname: orderer2</span></code></pre></td></tr></table></div></figure>


<p>PeerOrgs的配置信息</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>PeerOrgs:
</span><span class='line'>  - Name: Org1 #组织1
</span><span class='line'>    Domain: org1.xuyao.com
</span><span class='line'>    EnableNodeOUs: true
</span><span class='line'>    Template:
</span><span class='line'>      Count: 2
</span><span class='line'>    Users:
</span><span class='line'>      Count: 1
</span><span class='line'>  - Name: Org2 #组织2
</span><span class='line'>    Domain: org2.xuyao.com
</span><span class='line'>    EnableNodeOUs: true
</span><span class='line'>    Template:
</span><span class='line'>      Count: 2
</span><span class='line'>    Users:
</span><span class='line'>      Count: 1</span></code></pre></td></tr></table></div></figure>


<h5>5.1.2 使用generateArtifacts.sh脚本生成证书文件</h5>

<p>&emsp; 现在我们需要生成一些证书和启动这个fabric网络，生成证书的话我们可以使用官网提供的generateArtifacts.sh脚本来生成，文件路径在/gopath/src/github.com/hyperledger/fabric/examples/e2e_cli/下，稍微修改，因为我只需要生成证书，创世纪块，和channel.tx,具体脚本如下，<strong>需要说明的是如果你只是运行官方的first-network，可以忽略这些配置，因为first-network已经帮你生成好了这些东西</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>#!/usr/bin/env bash
</span><span class='line'>CRYPTOGEN=$PWD/bin/cryptogen
</span><span class='line'>CONFIGTXGEN=$PWD/bin/configtxgen
</span><span class='line'>CHANNEL_NAME=$1
</span><span class='line'>: ${CHANNEL_NAME:="mychannel"}
</span><span class='line'>function buildCryptogenTools(){
</span><span class='line'>  if [ -f "$CONFIGTXGEN" ]; then
</span><span class='line'>      echo
</span><span class='line'>  else
</span><span class='line'>      echo "configtxgen not found"
</span><span class='line'>      exit 1
</span><span class='line'>  fi
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>function createPeerTemplate() {
</span><span class='line'>    cp ../docker-composer-peer-template.yaml ../docker-composer
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>## Generates Org certs using cryptogen tool
</span><span class='line'>function generateCerts (){
</span><span class='line'>  echo
</span><span class='line'>  echo "##########################################################"
</span><span class='line'>  echo "##### Generate certificates using cryptogen tool #########"
</span><span class='line'>  echo "##########################################################"
</span><span class='line'>  if [ -d "crypto-config" ]; then
</span><span class='line'>      rm -Rf crypto-config
</span><span class='line'>    fi
</span><span class='line'>  ${CRYPTOGEN} generate --config=./crypto-config.yaml
</span><span class='line'>  echo
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>## Generate orderer genesis block , channel configuration transaction and anchor peer update transactions
</span><span class='line'>function generateChannelArtifacts() {
</span><span class='line'>  echo "##########################################################"
</span><span class='line'>  echo "#########  Generating Orderer Genesis block ##############"
</span><span class='line'>  echo "##########################################################"
</span><span class='line'>  ${CONFIGTXGEN} -profile TwoOrgsOrdererGenesis -outputBlock ./genesis.block
</span><span class='line'>
</span><span class='line'>  echo
</span><span class='line'>  echo "#################################################################"
</span><span class='line'>  echo "### Generating channel configuration transaction 'channel.tx' ###"
</span><span class='line'>  echo "#################################################################"
</span><span class='line'>  ${CONFIGTXGEN} -profile TwoOrgsChannel -outputCreateChannelTx ./mychannel.tx -channelID ${CHANNEL_NAME} 
</span><span class='line'>}
</span><span class='line'>
</span><span class='line'>buildCryptogenTools
</span><span class='line'>generateCerts
</span><span class='line'>generateChannelArtifacts</span></code></pre></td></tr></table></div></figure>


<p>generateCerts是生成证书的方法，它会加载crypto-config.yaml里的配置信息，并根据你的配置信息来生成相应的证书。<br/>
generateChannelArtifacts是生成orderer的创世纪块（genesis.block）和channel.tx文件。<br/>
上面的脚本运行之后，整个Fabric网络需要的一些证书就完成了，以本地例子为例，生成如下的一些文件数据</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
<span class='line-number'>100</span>
<span class='line-number'>101</span>
<span class='line-number'>102</span>
<span class='line-number'>103</span>
<span class='line-number'>104</span>
<span class='line-number'>105</span>
<span class='line-number'>106</span>
<span class='line-number'>107</span>
<span class='line-number'>108</span>
<span class='line-number'>109</span>
<span class='line-number'>110</span>
<span class='line-number'>111</span>
<span class='line-number'>112</span>
<span class='line-number'>113</span>
<span class='line-number'>114</span>
<span class='line-number'>115</span>
<span class='line-number'>116</span>
<span class='line-number'>117</span>
<span class='line-number'>118</span>
<span class='line-number'>119</span>
<span class='line-number'>120</span>
<span class='line-number'>121</span>
<span class='line-number'>122</span>
<span class='line-number'>123</span>
<span class='line-number'>124</span>
<span class='line-number'>125</span>
<span class='line-number'>126</span>
<span class='line-number'>127</span>
<span class='line-number'>128</span>
<span class='line-number'>129</span>
<span class='line-number'>130</span>
<span class='line-number'>131</span>
<span class='line-number'>132</span>
<span class='line-number'>133</span>
<span class='line-number'>134</span>
<span class='line-number'>135</span>
<span class='line-number'>136</span>
<span class='line-number'>137</span>
<span class='line-number'>138</span>
<span class='line-number'>139</span>
<span class='line-number'>140</span>
<span class='line-number'>141</span>
<span class='line-number'>142</span>
<span class='line-number'>143</span>
<span class='line-number'>144</span>
<span class='line-number'>145</span>
<span class='line-number'>146</span>
<span class='line-number'>147</span>
<span class='line-number'>148</span>
<span class='line-number'>149</span>
<span class='line-number'>150</span>
<span class='line-number'>151</span>
<span class='line-number'>152</span>
<span class='line-number'>153</span>
<span class='line-number'>154</span>
<span class='line-number'>155</span>
<span class='line-number'>156</span>
<span class='line-number'>157</span>
<span class='line-number'>158</span>
<span class='line-number'>159</span>
<span class='line-number'>160</span>
<span class='line-number'>161</span>
<span class='line-number'>162</span>
<span class='line-number'>163</span>
<span class='line-number'>164</span>
<span class='line-number'>165</span>
<span class='line-number'>166</span>
<span class='line-number'>167</span>
<span class='line-number'>168</span>
<span class='line-number'>169</span>
<span class='line-number'>170</span>
<span class='line-number'>171</span>
<span class='line-number'>172</span>
<span class='line-number'>173</span>
<span class='line-number'>174</span>
<span class='line-number'>175</span>
<span class='line-number'>176</span>
<span class='line-number'>177</span>
<span class='line-number'>178</span>
<span class='line-number'>179</span>
<span class='line-number'>180</span>
<span class='line-number'>181</span>
<span class='line-number'>182</span>
<span class='line-number'>183</span>
<span class='line-number'>184</span>
<span class='line-number'>185</span>
<span class='line-number'>186</span>
<span class='line-number'>187</span>
<span class='line-number'>188</span>
<span class='line-number'>189</span>
<span class='line-number'>190</span>
<span class='line-number'>191</span>
<span class='line-number'>192</span>
<span class='line-number'>193</span>
<span class='line-number'>194</span>
<span class='line-number'>195</span>
<span class='line-number'>196</span>
<span class='line-number'>197</span>
<span class='line-number'>198</span>
<span class='line-number'>199</span>
<span class='line-number'>200</span>
<span class='line-number'>201</span>
<span class='line-number'>202</span>
<span class='line-number'>203</span>
<span class='line-number'>204</span>
<span class='line-number'>205</span>
<span class='line-number'>206</span>
<span class='line-number'>207</span>
<span class='line-number'>208</span>
<span class='line-number'>209</span>
<span class='line-number'>210</span>
<span class='line-number'>211</span>
<span class='line-number'>212</span>
<span class='line-number'>213</span>
<span class='line-number'>214</span>
<span class='line-number'>215</span>
<span class='line-number'>216</span>
<span class='line-number'>217</span>
<span class='line-number'>218</span>
<span class='line-number'>219</span>
<span class='line-number'>220</span>
<span class='line-number'>221</span>
<span class='line-number'>222</span>
<span class='line-number'>223</span>
<span class='line-number'>224</span>
<span class='line-number'>225</span>
<span class='line-number'>226</span>
<span class='line-number'>227</span>
<span class='line-number'>228</span>
<span class='line-number'>229</span>
<span class='line-number'>230</span>
<span class='line-number'>231</span>
<span class='line-number'>232</span>
<span class='line-number'>233</span>
<span class='line-number'>234</span>
<span class='line-number'>235</span>
<span class='line-number'>236</span>
<span class='line-number'>237</span>
<span class='line-number'>238</span>
<span class='line-number'>239</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>├── crypto-config
</span><span class='line'>│   ├── ordererOrganizations
</span><span class='line'>│   │   └── mbasechain.com
</span><span class='line'>│   │       ├── ca
</span><span class='line'>│   │       │   ├── 2ae1db347d3137d66fda66f59fb33cd2c3c22a4aadf7f97f800491fb91a20c32_sk
</span><span class='line'>│   │       │   └── ca.mbasechain.com-cert.pem
</span><span class='line'>│   │       ├── msp
</span><span class='line'>│   │       │   ├── admincerts
</span><span class='line'>│   │       │   │   └── Admin@mbasechain.com-cert.pem
</span><span class='line'>│   │       │   ├── cacerts
</span><span class='line'>│   │       │   │   └── ca.mbasechain.com-cert.pem
</span><span class='line'>│   │       │   └── tlscacerts
</span><span class='line'>│   │       │       └── tlsca.mbasechain.com-cert.pem
</span><span class='line'>│   │       ├── orderers
</span><span class='line'>│   │       │   ├── orderer.mbasechain.com
</span><span class='line'>│   │       │   │   └── msp
</span><span class='line'>│   │       │   │       └── keystore
</span><span class='line'>│   │       │   ├── orderer1.mbasechain.com
</span><span class='line'>│   │       │   │   ├── msp
</span><span class='line'>│   │       │   │   │   ├── admincerts
</span><span class='line'>│   │       │   │   │   │   └── Admin@mbasechain.com-cert.pem
</span><span class='line'>│   │       │   │   │   ├── cacerts
</span><span class='line'>│   │       │   │   │   │   └── ca.mbasechain.com-cert.pem
</span><span class='line'>│   │       │   │   │   ├── keystore
</span><span class='line'>│   │       │   │   │   │   └── 9af18a6c9dd8f34db73a70c1d066e6948216db534af9e4f89029158089d56cf1_sk
</span><span class='line'>│   │       │   │   │   ├── signcerts
</span><span class='line'>│   │       │   │   │   │   └── orderer1.mbasechain.com-cert.pem
</span><span class='line'>│   │       │   │   │   └── tlscacerts
</span><span class='line'>│   │       │   │   │       └── tlsca.mbasechain.com-cert.pem
</span><span class='line'>│   │       │   │   └── tls
</span><span class='line'>│   │       │   │       ├── ca.crt
</span><span class='line'>│   │       │   │       ├── server.crt
</span><span class='line'>│   │       │   │       └── server.key
</span><span class='line'>│   │       │   └── orderer2.mbasechain.com
</span><span class='line'>│   │       │       ├── msp
</span><span class='line'>│   │       │       │   ├── admincerts
</span><span class='line'>│   │       │       │   │   └── Admin@mbasechain.com-cert.pem
</span><span class='line'>│   │       │       │   ├── cacerts
</span><span class='line'>│   │       │       │   │   └── ca.mbasechain.com-cert.pem
</span><span class='line'>│   │       │       │   ├── keystore
</span><span class='line'>│   │       │       │   │   └── fb54a7774228bf31311b5aa0ab58b4c0d3f9aa0e83bb1906cb6926c033445976_sk
</span><span class='line'>│   │       │       │   ├── signcerts
</span><span class='line'>│   │       │       │   │   └── orderer2.mbasechain.com-cert.pem
</span><span class='line'>│   │       │       │   └── tlscacerts
</span><span class='line'>│   │       │       │       └── tlsca.mbasechain.com-cert.pem
</span><span class='line'>│   │       │       └── tls
</span><span class='line'>│   │       │           ├── ca.crt
</span><span class='line'>│   │       │           ├── server.crt
</span><span class='line'>│   │       │           └── server.key
</span><span class='line'>│   │       ├── tlsca
</span><span class='line'>│   │       │   ├── 9ceda704a49805f19c0f3cde2c1d42096d8e14da697567b0a02b051656f735de_sk
</span><span class='line'>│   │       │   └── tlsca.mbasechain.com-cert.pem
</span><span class='line'>│   │       └── users
</span><span class='line'>│   │           └── Admin@mbasechain.com
</span><span class='line'>│   │               ├── msp
</span><span class='line'>│   │               │   ├── admincerts
</span><span class='line'>│   │               │   │   └── Admin@mbasechain.com-cert.pem
</span><span class='line'>│   │               │   ├── cacerts
</span><span class='line'>│   │               │   │   └── ca.mbasechain.com-cert.pem
</span><span class='line'>│   │               │   ├── keystore
</span><span class='line'>│   │               │   │   └── 1c7c1a76c08e30990192ed0f6eb24c2efd7492b684f92ebf844591fb38d8b020_sk
</span><span class='line'>│   │               │   ├── signcerts
</span><span class='line'>│   │               │   │   └── Admin@mbasechain.com-cert.pem
</span><span class='line'>│   │               │   └── tlscacerts
</span><span class='line'>│   │               │       └── tlsca.mbasechain.com-cert.pem
</span><span class='line'>│   │               └── tls
</span><span class='line'>│   │                   ├── ca.crt
</span><span class='line'>│   │                   ├── client.crt
</span><span class='line'>│   │                   └── client.key
</span><span class='line'>│   └── peerOrganizations
</span><span class='line'>│       ├── org1.mbasechain.com
</span><span class='line'>│       │   ├── ca
</span><span class='line'>│       │   │   ├── 6cb226be4aec981541e6cbdd66742139c1157e88afe06edfb16f12ecc3056bf5_sk
</span><span class='line'>│       │   │   └── ca.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │   ├── msp
</span><span class='line'>│       │   │   ├── admincerts
</span><span class='line'>│       │   │   │   └── Admin@org1.mbasechain.com-cert.pem
</span><span class='line'>│       │   │   ├── cacerts
</span><span class='line'>│       │   │   │   └── ca.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │   │   ├── config.yaml
</span><span class='line'>│       │   │   └── tlscacerts
</span><span class='line'>│       │   │       └── tlsca.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │   ├── peers
</span><span class='line'>│       │   │   ├── peer0.org1.mbasechain.com
</span><span class='line'>│       │   │   │   ├── msp
</span><span class='line'>│       │   │   │   │   ├── admincerts
</span><span class='line'>│       │   │   │   │   │   └── Admin@org1.mbasechain.com-cert.pem
</span><span class='line'>│       │   │   │   │   ├── cacerts
</span><span class='line'>│       │   │   │   │   │   └── ca.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │   │   │   │   ├── config.yaml
</span><span class='line'>│       │   │   │   │   ├── keystore
</span><span class='line'>│       │   │   │   │   │   └── b9d2875104a103f635c8ec21757710455eec0fbfb2c59f7b33a09461b4138267_sk
</span><span class='line'>│       │   │   │   │   ├── signcerts
</span><span class='line'>│       │   │   │   │   │   └── peer0.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │   │   │   │   └── tlscacerts
</span><span class='line'>│       │   │   │   │       └── tlsca.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │   │   │   └── tls
</span><span class='line'>│       │   │   │       ├── ca.crt
</span><span class='line'>│       │   │   │       ├── server.crt
</span><span class='line'>│       │   │   │       └── server.key
</span><span class='line'>│       │   │   └── peer1.org1.mbasechain.com
</span><span class='line'>│       │   │       ├── msp
</span><span class='line'>│       │   │       │   ├── admincerts
</span><span class='line'>│       │   │       │   │   └── Admin@org1.mbasechain.com-cert.pem
</span><span class='line'>│       │   │       │   ├── cacerts
</span><span class='line'>│       │   │       │   │   └── ca.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │   │       │   ├── config.yaml
</span><span class='line'>│       │   │       │   ├── keystore
</span><span class='line'>│       │   │       │   │   └── 68da53988aa0b3e50b6a90ac90495b4021fdb3456bbca375aca13cf206d18b0c_sk
</span><span class='line'>│       │   │       │   ├── signcerts
</span><span class='line'>│       │   │       │   │   └── peer1.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │   │       │   └── tlscacerts
</span><span class='line'>│       │   │       │       └── tlsca.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │   │       └── tls
</span><span class='line'>│       │   │           ├── ca.crt
</span><span class='line'>│       │   │           ├── server.crt
</span><span class='line'>│       │   │           └── server.key
</span><span class='line'>│       │   ├── tlsca
</span><span class='line'>│       │   │   ├── b2ef19d2488129396546090955ddf2d1ec267cd699dc2218516df72f5ea235f4_sk
</span><span class='line'>│       │   │   └── tlsca.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │   └── users
</span><span class='line'>│       │       ├── Admin@org1.mbasechain.com
</span><span class='line'>│       │       │   ├── msp
</span><span class='line'>│       │       │   │   ├── admincerts
</span><span class='line'>│       │       │   │   │   └── Admin@org1.mbasechain.com-cert.pem
</span><span class='line'>│       │       │   │   ├── cacerts
</span><span class='line'>│       │       │   │   │   └── ca.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │       │   │   ├── keystore
</span><span class='line'>│       │       │   │   │   └── 12f72b7332170a7b8e4214eb268c419053a2386f34b149f3e7c5820f767a2d30_sk
</span><span class='line'>│       │       │   │   ├── signcerts
</span><span class='line'>│       │       │   │   │   └── Admin@org1.mbasechain.com-cert.pem
</span><span class='line'>│       │       │   │   └── tlscacerts
</span><span class='line'>│       │       │   │       └── tlsca.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │       │   └── tls
</span><span class='line'>│       │       │       ├── ca.crt
</span><span class='line'>│       │       │       ├── client.crt
</span><span class='line'>│       │       │       └── client.key
</span><span class='line'>│       │       └── User1@org1.mbasechain.com
</span><span class='line'>│       │           ├── msp
</span><span class='line'>│       │           │   ├── admincerts
</span><span class='line'>│       │           │   │   └── User1@org1.mbasechain.com-cert.pem
</span><span class='line'>│       │           │   ├── cacerts
</span><span class='line'>│       │           │   │   └── ca.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │           │   ├── keystore
</span><span class='line'>│       │           │   │   └── 610899489aa3d881dcc6e9f3d421981003b1504e5b15c00426edd69505ef3519_sk
</span><span class='line'>│       │           │   ├── signcerts
</span><span class='line'>│       │           │   │   └── User1@org1.mbasechain.com-cert.pem
</span><span class='line'>│       │           │   └── tlscacerts
</span><span class='line'>│       │           │       └── tlsca.org1.mbasechain.com-cert.pem
</span><span class='line'>│       │           └── tls
</span><span class='line'>│       │               ├── ca.crt
</span><span class='line'>│       │               ├── client.crt
</span><span class='line'>│       │               └── client.key
</span><span class='line'>│       ├── org2.mbasechain.com
</span><span class='line'>│       │   ├── ca
</span><span class='line'>│       │   │   ├── 018041cad6bac4a43ab80e736ba333a759a14ee6e88226944ec904dfcba633ab_sk
</span><span class='line'>│       │   │   └── ca.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │   ├── msp
</span><span class='line'>│       │   │   ├── admincerts
</span><span class='line'>│       │   │   │   └── Admin@org2.mbasechain.com-cert.pem
</span><span class='line'>│       │   │   ├── cacerts
</span><span class='line'>│       │   │   │   └── ca.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │   │   ├── config.yaml
</span><span class='line'>│       │   │   └── tlscacerts
</span><span class='line'>│       │   │       └── tlsca.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │   ├── peers
</span><span class='line'>│       │   │   ├── peer0.org2.mbasechain.com
</span><span class='line'>│       │   │   │   ├── msp
</span><span class='line'>│       │   │   │   │   ├── admincerts
</span><span class='line'>│       │   │   │   │   │   └── Admin@org2.mbasechain.com-cert.pem
</span><span class='line'>│       │   │   │   │   ├── cacerts
</span><span class='line'>│       │   │   │   │   │   └── ca.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │   │   │   │   ├── config.yaml
</span><span class='line'>│       │   │   │   │   ├── keystore
</span><span class='line'>│       │   │   │   │   │   └── cfb79d8ab3c543a8732227cd2b441ce30e82ff1d4aad5f59c1338454edeeddf1_sk
</span><span class='line'>│       │   │   │   │   ├── signcerts
</span><span class='line'>│       │   │   │   │   │   └── peer0.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │   │   │   │   └── tlscacerts
</span><span class='line'>│       │   │   │   │       └── tlsca.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │   │   │   └── tls
</span><span class='line'>│       │   │   │       ├── ca.crt
</span><span class='line'>│       │   │   │       ├── server.crt
</span><span class='line'>│       │   │   │       └── server.key
</span><span class='line'>│       │   │   └── peer1.org2.mbasechain.com
</span><span class='line'>│       │   │       ├── msp
</span><span class='line'>│       │   │       │   ├── admincerts
</span><span class='line'>│       │   │       │   │   └── Admin@org2.mbasechain.com-cert.pem
</span><span class='line'>│       │   │       │   ├── cacerts
</span><span class='line'>│       │   │       │   │   └── ca.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │   │       │   ├── config.yaml
</span><span class='line'>│       │   │       │   ├── keystore
</span><span class='line'>│       │   │       │   │   └── b92cbb64895e522299770c9f84ad9954753f348d926da956d4458cf545b99ef6_sk
</span><span class='line'>│       │   │       │   ├── signcerts
</span><span class='line'>│       │   │       │   │   └── peer1.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │   │       │   └── tlscacerts
</span><span class='line'>│       │   │       │       └── tlsca.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │   │       └── tls
</span><span class='line'>│       │   │           ├── ca.crt
</span><span class='line'>│       │   │           ├── server.crt
</span><span class='line'>│       │   │           └── server.key
</span><span class='line'>│       │   ├── tlsca
</span><span class='line'>│       │   │   ├── 2674e511ae5eb66b4964a2a93cc917f5e8fbd49e95fc97d12b546c9ce933e932_sk
</span><span class='line'>│       │   │   └── tlsca.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │   └── users
</span><span class='line'>│       │       ├── Admin@org2.mbasechain.com
</span><span class='line'>│       │       │   ├── msp
</span><span class='line'>│       │       │   │   ├── admincerts
</span><span class='line'>│       │       │   │   │   └── Admin@org2.mbasechain.com-cert.pem
</span><span class='line'>│       │       │   │   ├── cacerts
</span><span class='line'>│       │       │   │   │   └── ca.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │       │   │   ├── keystore
</span><span class='line'>│       │       │   │   │   └── 4ca087cf7e8ecd260b84782ec8456b693ada673b902d525fb0dfcbf4bc797e38_sk
</span><span class='line'>│       │       │   │   ├── signcerts
</span><span class='line'>│       │       │   │   │   └── Admin@org2.mbasechain.com-cert.pem
</span><span class='line'>│       │       │   │   └── tlscacerts
</span><span class='line'>│       │       │   │       └── tlsca.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │       │   └── tls
</span><span class='line'>│       │       │       ├── ca.crt
</span><span class='line'>│       │       │       ├── client.crt
</span><span class='line'>│       │       │       └── client.key
</span><span class='line'>│       │       └── User1@org2.mbasechain.com
</span><span class='line'>│       │           ├── msp
</span><span class='line'>│       │           │   ├── admincerts
</span><span class='line'>│       │           │   │   └── User1@org2.mbasechain.com-cert.pem
</span><span class='line'>│       │           │   ├── cacerts
</span><span class='line'>│       │           │   │   └── ca.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │           │   ├── keystore
</span><span class='line'>│       │           │   │   └── 950ff48168df356652a4fa6d5f9d3aa7d6d7694045cc3bb7f83587686794a345_sk
</span><span class='line'>│       │           │   ├── signcerts
</span><span class='line'>│       │           │   │   └── User1@org2.mbasechain.com-cert.pem
</span><span class='line'>│       │           │   └── tlscacerts
</span><span class='line'>│       │           │       └── tlsca.org2.mbasechain.com-cert.pem
</span><span class='line'>│       │           └── tls
</span><span class='line'>│       │               ├── ca.crt
</span><span class='line'>│       │               ├── client.crt
</span><span class='line'>│       │               └── client.key
</span><span class='line'>├── crypto-config.yaml
</span><span class='line'>├── genesis.block
</span><span class='line'>├── mychannel.tx</span></code></pre></td></tr></table></div></figure>


<h5>未完待续。。。</h5>

<h5>参考资料</h5>

<p><a href="https://hyperledgercn.github.io/hyperledgerDocs/getting_started/">https://hyperledgercn.github.io/hyperledgerDocs/getting_started/</a><br/>
<a href="https://www.codetd.com/article/2709144">https://www.codetd.com/article/2709144</a><br/>
<a href="https://hyperledgercn.github.io/hyperledgerDocs/build_network_zh/">https://hyperledgercn.github.io/hyperledgerDocs/build_network_zh/</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Fabric多台服务器的部署(一)]]></title>
    <link href="http://xuyao.club/blog/2018/12/14/deployment-of-fabric-multiple-servers-i/"/>
    <updated>2018-12-14T11:55:10+08:00</updated>
    <id>http://xuyao.club/blog/2018/12/14/deployment-of-fabric-multiple-servers-i</id>
    <content type="html"><![CDATA[<h3>1、前言</h3>

<p>  &emsp;Hyperledger Fabric是一个提供分布式账本解决方案的平台。Hyperledger Fabric由模块化架构支撑，并具备极佳的保密性、可伸缩性、灵活性和可扩展性。Hyperledger Fabric被设计成支持不同的模块组件直接拔插启用，并能适应在经济生态系统中错综复杂的各种场景。
 &emsp;目前Fabric在区块链溯源场景应用的挺多，农产品，奢侈品，艺术品，红酒等方面都看过到案例，区块链可以保存产品各个环节的数据，并上链，用户最后可能只需扫描一个二维码，就可以查出某个产品整个的生产过程，与中心化数据不同的是，区块链溯源项目数据一旦上链后不可更改，而且数据公开透明，任何一方都没有权利来更改它，同时每个环节需要为你上链的数据负责，如果哪天消费查出某个环节的数据是假的，由于账本数据是分布式的、不可更改的，大家只相信数据，商家也无法抵赖，最后商家只能认错，名誉扫地，所以区块链本质上是解决一个多方协作的一个信任问题，而对于一件事情需要多方协作，共同记账来一起完成的，Fabric作为联盟链，显然很符合这种需求。</p>

<!-- more -->


<p></p>

<h3>2、环境安装及服务器配置</h3>

<h5>2.1 环境安装</h5>

<p>在配置Fabric网络之前，需要安装一下相关环境，包括GO语言安装和Docker的安装</p>

<h6>2.1.1 GO语言安装</h6>

<p>1、从官网下载它的安装包，地址：<a href="https://golang.org/dl/">https://golang.org/dl/</a>，根据自己电脑或服务器不同系统下载对应的安装包。
2、下载后解压包</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>tar -C /usr/local -xzf go$VERSION.$OS-$ARCH.tar.gz</span></code></pre></td></tr></table></div></figure>


<p>3、配置GO的环境变量</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>export PATH=$PATH:/usr/local/go/bin
</span><span class='line'>export GOPATH=/opt/gopath</span></code></pre></td></tr></table></div></figure>


<p>最后执行source命令，使其生效</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>source profile</span></code></pre></td></tr></table></div></figure>


<p>最后打印一下GO版本</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>go version
</span><span class='line'>go version go1.10.1 darwin/amd64</span></code></pre></td></tr></table></div></figure>


<p><strong>ubuntu系统下安装</strong></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>sudo add-apt-repository ppa:longsleep/golang-backports
</span><span class='line'>sudo apt-get update
</span><span class='line'>sudo apt-get install golang-go</span></code></pre></td></tr></table></div></figure>


<p>设置环境变量</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>export GOPATH=$HOME/go
</span><span class='line'>export PATH=$PATH:$GOROOT/bin:$GOPATH/bin</span></code></pre></td></tr></table></div></figure>


<p>不同系统安装略有不同，具体建议查看官方文档 <a href="https://golang.org/doc/install">https://golang.org/doc/install</a></p>

<h5>2.1.2 Docker、Docker-Compose的安装</h5>

<p>docker安装不同系统也是有区别的，我是mac电脑，安装也相对简单，到docker<a href="https://www.docker.com/products/docker-desktop">官网</a>下载一个包，直接安装就行，装好后可以查一下docker的版本，值得注意的是，mac电脑只安装docker就行，docker版本已经包括了compose和其它docker应用，所以无需再另行安装compose</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>docker version
</span><span class='line'>#docker的版本信息
</span><span class='line'>Client:
</span><span class='line'> Version:           18.06.1-ce
</span><span class='line'> API version:       1.38
</span><span class='line'> Go version:        go1.10.3
</span><span class='line'> Git commit:        e68fc7a
</span><span class='line'> Built:             Tue Aug 21 17:21:31 2018
</span><span class='line'> OS/Arch:           darwin/amd64
</span><span class='line'> Experimental:      false
</span><span class='line'>
</span><span class='line'>Server:
</span><span class='line'> Engine:
</span><span class='line'>  Version:          18.06.1-ce
</span><span class='line'>  API version:      1.38 (minimum version 1.12)
</span><span class='line'>  Go version:       go1.10.3
</span><span class='line'>  Git commit:       e68fc7a
</span><span class='line'>  Built:            Tue Aug 21 17:29:02 2018
</span><span class='line'>  OS/Arch:          linux/amd64
</span><span class='line'>  Experimental:     true</span></code></pre></td></tr></table></div></figure>


<p>如果是Linux系统，需要安装docker和docker-compose，可以参考这里<a href="https://yeasy.gitbooks.io/docker_practice/install/">https://yeasy.gitbooks.io/docker_practice/install/</a>,针对不同的linux系统，都有安装方法，写的比较详细，也可以参考官网信息<a href="https://docs.docker.com/compose/install/">https://docs.docker.com/compose/install/</a></p>

<p><strong>ubuntu系统安装docker、docker-compose</strong></p>

<p>卸载旧版本的docker</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ sudo apt-get remove docker \
</span><span class='line'>               docker-engine \
</span><span class='line'>               docker.io</span></code></pre></td></tr></table></div></figure>


<p>鉴于国内网络问题，强烈建议使用国内源，官方源请在注释中查看。
为了确认所下载软件包的合法性，需要添加软件源的 GPG 密钥。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
</span><span class='line'>$ sudo add-apt-repository \
</span><span class='line'>    "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu \
</span><span class='line'>    $(lsb_release -cs) \
</span><span class='line'>    stable"</span></code></pre></td></tr></table></div></figure>


<p>安装docker-ce</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ sudo apt-get update
</span><span class='line'>
</span><span class='line'>$ sudo apt-get install docker-ce</span></code></pre></td></tr></table></div></figure>


<p>安装docker-compose，在 Linux 上的也安装十分简单，从 <a href="https://github.com/docker/compose/releases">官方 GitHub Release</a> 处直接下载编译好的二进制文件即可。
例如，在 Linux 64 位系统上直接下载对应的二进制包。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -L https://github.com/docker/compose/releases/download/1.23.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
</span><span class='line'>chmod +x /usr/local/bin/docker-compose</span></code></pre></td></tr></table></div></figure>


<h5>2.1.3 nodejs安装</h5>

<p> &emsp;因为我们项目用的是nodejs SDK，所以实际项目中还需要安装nodejs和npm来跑项目，因为Fabric目前只支持nodejs v8.4.0~v9.0.0的版本（2018-10），所以建议安装的时候指定一个固定的版本，比如v8.9.0，我用的是这个版本，还是很稳定的，当然也可以先下载一个nvm来管理nodejs的版本，不同项目需要不同的node版本，使用nvm可以管理不同的node版本。
1、安装nvm，执行下面命令下载安装脚本</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
</span><span class='line'>#输出
</span><span class='line'>
</span><span class='line'>=&gt; Close and reopen your terminal to start using nvm or run the following to use it now:
</span><span class='line'>export NVM_DIR="$HOME/.nvm"
</span><span class='line'>[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
</span><span class='line'>[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion</span></code></pre></td></tr></table></div></figure>


<p>检查下是否安装成功</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>nvm --version
</span><span class='line'>0.33.11</span></code></pre></td></tr></table></div></figure>


<p>2、安装nodejs，使用nvm ls-remote查看远程可安装的node版本</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>nvm ls-remote 
</span><span class='line'>v8.0.0
</span><span class='line'>v8.1.0
</span><span class='line'>v8.1.1
</span><span class='line'>v8.1.2
</span><span class='line'>v8.1.3
</span><span class='line'>v8.1.4
</span><span class='line'>v8.2.0
</span><span class='line'>v8.2.1
</span><span class='line'>v8.3.0
</span><span class='line'>v8.4.0
</span><span class='line'>v8.5.0
</span><span class='line'>v8.6.0
</span><span class='line'>v8.7.0
</span><span class='line'>v8.8.0
</span><span class='line'>v8.8.1
</span><span class='line'>v8.9.0</span></code></pre></td></tr></table></div></figure>


<p>找到自己想要安装的版本来安装nodejs</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>nvm install 8.9.0</span></code></pre></td></tr></table></div></figure>


<p>使用node命令查看是否安装成功</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>node -v
</span><span class='line'>v8.9.1</span></code></pre></td></tr></table></div></figure>


<p>也可以使用nvm ls来查看当前环境有几个node版本</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>nvm ls
</span><span class='line'>
</span><span class='line'>-&gt;       v8.9.1
</span><span class='line'>         system
</span><span class='line'>default -&gt; 8.9.1 (-&gt; v8.9.1)
</span><span class='line'>node -&gt; stable (-&gt; v8.9.1) (default)
</span><span class='line'>stable -&gt; 8.9 (-&gt; v8.9.1) (default)
</span><span class='line'>iojs -&gt; N/A (default)
</span><span class='line'>lts/* -&gt; lts/dubnium (-&gt; N/A)
</span><span class='line'>lts/argon -&gt; v4.9.1 (-&gt; N/A)
</span><span class='line'>lts/boron -&gt; v6.15.0 (-&gt; N/A)
</span><span class='line'>lts/carbon -&gt; v8.14.0 (-&gt; N/A)
</span><span class='line'>lts/dubnium -&gt; v10.14.1 (-&gt; N/A)</span></code></pre></td></tr></table></div></figure>


<p>可以看到目前只安装了8.9.0，而且系统默认使用的就是8.9.0，如果想改变系统的默认版本，可以使用如下命令</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>nvm use 8.9.0
</span><span class='line'>Now using node v10.13.0 (npm v6.4.1)</span></code></pre></td></tr></table></div></figure>


<h5>2.1.4 Git工具安装</h5>

<p>Git安装就简单了吧，做过开发的人应该都安装过，这里贴个安装教程，
<a href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git">https://git-scm.com/book/en/v2/Getting-Started-Installing-Git</a>,跟着上面安装就行。</p>

<h5>2.2 服务器配置说明</h5>

<p> &emsp;说明一下服务器的整个情况，我申请了4台服务器， 做4个peer，两个orderer，具体的crypto-config.yaml配置如下：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
<span class='line-number'>54</span>
<span class='line-number'>55</span>
<span class='line-number'>56</span>
<span class='line-number'>57</span>
<span class='line-number'>58</span>
<span class='line-number'>59</span>
<span class='line-number'>60</span>
<span class='line-number'>61</span>
<span class='line-number'>62</span>
<span class='line-number'>63</span>
<span class='line-number'>64</span>
<span class='line-number'>65</span>
<span class='line-number'>66</span>
<span class='line-number'>67</span>
<span class='line-number'>68</span>
<span class='line-number'>69</span>
<span class='line-number'>70</span>
<span class='line-number'>71</span>
<span class='line-number'>72</span>
<span class='line-number'>73</span>
<span class='line-number'>74</span>
<span class='line-number'>75</span>
<span class='line-number'>76</span>
<span class='line-number'>77</span>
<span class='line-number'>78</span>
<span class='line-number'>79</span>
<span class='line-number'>80</span>
<span class='line-number'>81</span>
<span class='line-number'>82</span>
<span class='line-number'>83</span>
<span class='line-number'>84</span>
<span class='line-number'>85</span>
<span class='line-number'>86</span>
<span class='line-number'>87</span>
<span class='line-number'>88</span>
<span class='line-number'>89</span>
<span class='line-number'>90</span>
<span class='line-number'>91</span>
<span class='line-number'>92</span>
<span class='line-number'>93</span>
<span class='line-number'>94</span>
<span class='line-number'>95</span>
<span class='line-number'>96</span>
<span class='line-number'>97</span>
<span class='line-number'>98</span>
<span class='line-number'>99</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>
</span><span class='line'>OrdererOrgs:
</span><span class='line'>  # ---------------------------------------------------------------------------
</span><span class='line'>  # Orderer
</span><span class='line'>  # ---------------------------------------------------------------------------
</span><span class='line'>  - Name: Orderer
</span><span class='line'>    Domain: xuyao.com
</span><span class='line'>    # ---------------------------------------------------------------------------
</span><span class='line'>    # "Specs" - See PeerOrgs below for complete description
</span><span class='line'>    # ---------------------------------------------------------------------------
</span><span class='line'>    Specs:
</span><span class='line'>      - Hostname: orderer1
</span><span class='line'>      - Hostname: orderer2
</span><span class='line'># ---------------------------------------------------------------------------
</span><span class='line'># "PeerOrgs" - Definition of organizations managing peer nodes
</span><span class='line'># ---------------------------------------------------------------------------
</span><span class='line'>PeerOrgs:
</span><span class='line'>  # ---------------------------------------------------------------------------
</span><span class='line'>  # Org1
</span><span class='line'>  # ---------------------------------------------------------------------------
</span><span class='line'>  - Name: Org1
</span><span class='line'>    Domain: org1.xuyao.com
</span><span class='line'>    EnableNodeOUs: true
</span><span class='line'>    # ---------------------------------------------------------------------------
</span><span class='line'>    # "Specs"
</span><span class='line'>    # ---------------------------------------------------------------------------
</span><span class='line'>    # Uncomment this section to enable the explicit definition of hosts in your
</span><span class='line'>    # configuration.  Most users will want to use Template, below
</span><span class='line'>    #
</span><span class='line'>    # Specs is an array of Spec entries.  Each Spec entry consists of two fields:
</span><span class='line'>    #   - Hostname:   (Required) The desired hostname, sans the domain.
</span><span class='line'>    #   - CommonName: (Optional) Specifies the template or explicit override for
</span><span class='line'>    #                 the CN.  By default, this is the template:
</span><span class='line'>    #
</span><span class='line'>    #                              "."
</span><span class='line'>    #
</span><span class='line'>    #                 which obtains its values from the Spec.Hostname and
</span><span class='line'>    #                 Org.Domain, respectively.
</span><span class='line'>    # ---------------------------------------------------------------------------
</span><span class='line'>    # Specs:
</span><span class='line'>    #   - Hostname: foo # implicitly "foo.org1.example.com"
</span><span class='line'>    #     CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
</span><span class='line'>    #   - Hostname: bar
</span><span class='line'>    #   - Hostname: baz
</span><span class='line'>    # ---------------------------------------------------------------------------
</span><span class='line'>    # "Template"
</span><span class='line'>    # ---------------------------------------------------------------------------
</span><span class='line'>    # Allows for the definition of 1 or more hosts that are created sequentially
</span><span class='line'>    # from a template. By default, this looks like "peer%d" from 0 to Count-1.
</span><span class='line'>    # You may override the number of nodes (Count), the starting index (Start)
</span><span class='line'>    # or the template used to construct the name (Hostname).
</span><span class='line'>    #
</span><span class='line'>    # Note: Template and Specs are not mutually exclusive.  You may define both
</span><span class='line'>    # sections and the aggregate nodes will be created for you.  Take care with
</span><span class='line'>    # name collisions
</span><span class='line'>    # ---------------------------------------------------------------------------
</span><span class='line'>    Template:
</span><span class='line'>      Count: 2
</span><span class='line'>      # Start: 5
</span><span class='line'>      # Hostname:  # default
</span><span class='line'>    # ---------------------------------------------------------------------------
</span><span class='line'>    # "Users"
</span><span class='line'>    # ---------------------------------------------------------------------------
</span><span class='line'>    # Count: The number of user accounts _in addition_ to Admin
</span><span class='line'>    # ---------------------------------------------------------------------------
</span><span class='line'>    Users:
</span><span class='line'>      Count: 1
</span><span class='line'>  # ---------------------------------------------------------------------------
</span><span class='line'>  # Org2: See "Org1" for full specification
</span><span class='line'>  # ---------------------------------------------------------------------------
</span><span class='line'>  - Name: Org2
</span><span class='line'>    Domain: org2.xuyao.com
</span><span class='line'>    EnableNodeOUs: true
</span><span class='line'>    Template:
</span><span class='line'>      Count: 2
</span><span class='line'>    Users:
</span><span class='line'>      Count: 1
</span><span class='line'>
</span><span class='line'>  # ---------------------------------------------------------------------------
</span><span class='line'>  # Org3: See "Org1" for full specification
</span><span class='line'>  # ---------------------------------------------------------------------------
</span><span class='line'>  - Name: Org3
</span><span class='line'>    Domain: org3.xuyao.com
</span><span class='line'>    EnableNodeOUs: true
</span><span class='line'>    Template:
</span><span class='line'>      Count: 2
</span><span class='line'>    Users:
</span><span class='line'>      Count: 1
</span><span class='line'>
</span><span class='line'>  # ---------------------------------------------------------------------------
</span><span class='line'>  # Org4: See "Org1" for full specification
</span><span class='line'>  # ---------------------------------------------------------------------------
</span><span class='line'>  - Name: Org4
</span><span class='line'>    Domain: org4.xuyao.com
</span><span class='line'>    EnableNodeOUs: true
</span><span class='line'>    Template:
</span><span class='line'>      Count: 2
</span><span class='line'>    Users:
</span><span class='line'>      Count: 1</span></code></pre></td></tr></table></div></figure>


<p>每台服务器的运行大致如下</p>

<ol>
<li>server1: Org1, Peer1，Orderer1，Ca1，Kafka1, Zookeeper1</li>
<li>server1:  Org2, Peer2，Orderer2，Ca2，Kafka2, Zookeeper2</li>
<li>server3:  Org3, Peer3，Ca3，Kafka3, Zookeeper3</li>
<li>server4:  Org4, Peer4，Ca4，Kafka4<br/>
每台服务器一个Org组织，和一个节点， 其中两台服务器有Orderer服务，四台服务器都有Ca认证。

<h6>未完待续&hellip;..</h6></li>
</ol>


<h5>参考资料</h5>

<p><a href="https://golang.org/doc/install">https://golang.org/doc/install</a><br/>
<a href="https://github.com/golang/go/wiki/Ubuntu">https://github.com/golang/go/wiki/Ubuntu</a>
<a href="https://yeasy.gitbooks.io/docker_practice/install/">https://yeasy.gitbooks.io/docker_practice/install/</a><br/>
<a href="https://github.com/docker/compose/releases">https://github.com/docker/compose/releases</a>
<a href="https://linuxize.com/post/how-to-install-node-js-on-centos-7">https://linuxize.com/post/how-to-install-node-js-on-centos-7</a><br/>
<a href="https://git-scm.com/book/en/v2/Getting-Started-Installing-Git">https://git-scm.com/book/en/v2/Getting-Started-Installing-Git</a><br/>
<a href="https://www.cnblogs.com/aberic/p/7527831.html">https://www.cnblogs.com/aberic/p/7527831.html</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[密码学(二)之代换密码]]></title>
    <link href="http://xuyao.club/blog/2018/07/17/cryptography-of-substitution-cipher/"/>
    <updated>2018-07-17T17:28:46+08:00</updated>
    <id>http://xuyao.club/blog/2018/07/17/cryptography-of-substitution-cipher</id>
    <content type="html"><![CDATA[<h3>（一）代换密码（替换密码）</h3>

<p>上一讲中，我们讲移位密码其实是将字母表中的字母一一对应到各数字，然后通过数字平移来进行加密，古典密码学中还有一种比较有名的加密方法，就是将明文中的字母表对应到一套密文的字母表，这种加密方法我们叫<strong>代换密码（substiution cipher）</strong>或叫<strong>替换密码</strong>，下图就是一个简单的代换密码对应表</p>

<!-- more -->


<p></p>

<p><img src="http://upload-images.jianshu.io/upload_images/1796624-db5bd0e79f37103e?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image" /></p>

<h3>（二）代换密码的加密</h3>

<p>上面所说，代换密码其实就是将明文里的字母按照字母表替换成密文里的字母，还是举一个例子，假设现在有一个字符“welcome to china”，根据上面的密码替换表，将明文里面的每个字母依次换成对应的密文，如下：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">w</span><span class="o">-&gt;</span><span class="n">C</span>
</span><span class='line'><span class="n">e</span><span class="o">-&gt;</span><span class="n">X</span>
</span><span class='line'><span class="n">l</span><span class="o">-&gt;</span><span class="n">G</span>
</span><span class='line'><span class="n">c</span><span class="o">-&gt;</span><span class="n">H</span>
</span><span class='line'><span class="n">o</span><span class="o">-&gt;</span><span class="n">B</span>
</span><span class='line'><span class="n">m</span><span class="o">-&gt;</span><span class="n">E</span>
</span><span class='line'><span class="n">e</span><span class="o">-&gt;</span><span class="n">X</span>
</span><span class='line'><span class="n">t</span><span class="o">-&gt;</span><span class="n">Q</span>
</span><span class='line'><span class="n">o</span><span class="o">-&gt;</span><span class="n">B</span>
</span><span class='line'><span class="n">c</span><span class="o">-&gt;</span><span class="n">H</span>
</span><span class='line'><span class="n">h</span><span class="o">-&gt;</span><span class="n">T</span>
</span><span class='line'><span class="n">i</span><span class="o">-&gt;</span><span class="n">J</span>
</span><span class='line'><span class="n">n</span><span class="o">-&gt;</span><span class="n">N</span>
</span><span class='line'><span class="n">a</span><span class="o">-&gt;</span><span class="n">W</span>
</span></code></pre></td></tr></table></div></figure>


<p>这样就可以得到密文CXGHBEXQBHTJNW</p>

<h3>（三）代换密码的解密</h3>

<p>代换密码的解密非常简单，只要将加密的替换表进行反向操作，这里不再操作</p>

<p>这里可以发现，代换密码主要是要建立起一套明文与密文之间的加密对应的替换关系，只要有这套密码替换表，加、解密就变得很容易</p>

<h3>（四）代换密码的破解</h3>

<p>上一讲我们知道，移位密码其实是很好破解的，因为密钥总量一共就26位，只要我们试26次，就一定能试出一个正解的，那么代换密码是也可以通过穷举的方式来破解呢？</p>

<p>我们知道代换密码是把明文的26个字母随机对应密文的26个字母上，也就意味着明文中第一个字母a可以对应到密文中A,B,C,D…Z 26个字母中的任一个，以此类推，我们就可以计算出代换密码的密钥总数为：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="mi">26</span> <span class="n">x</span> <span class="mi">25</span> <span class="n">x</span> <span class="mi">24</span> <span class="n">x</span> <span class="mi">23</span> <span class="n">x22</span> <span class="n">x</span> <span class="mi">21</span> <span class="n">x</span> <span class="err">…</span> <span class="n">x</span> <span class="mi">1</span> <span class="o">=</span> <span class="mi">403291461126605635584000000</span>
</span></code></pre></td></tr></table></div></figure>


<p>像这种一种密码能够使用的所有密钥的集合，叫做<strong>密钥空间（keyspace）</strong></p>

<p>上面的密钥的量非常大，用穷举法来破译几乎是不可能的。</p>

<p>使用穷举法不能破译，但并不能说明就是安全的，我们可以使用<a href="https://baike.baidu.com/item/%E5%AD%97%E6%AF%8D%E9%A2%91%E7%8E%87/9669044?fr=aladdin">频率分析</a>来破译代换密码，频率分析就是利用明文中的字母出现频率与密文中的字母的出现频率一致这一特性，</p>

<p>下面是【密码学原理与实践】书中的一个例子，可以参考一下</p>

<p>现假设有一段密文如下，现需将其解密出明文</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">YIFQFMZRWQFYVECFMDZPCVMRZWNMDZVEJBTXCDDUMJ</span>
</span><span class='line'>
</span><span class='line'><span class="no">NDIFEFMDZCDMQZKCEYFCJMYRNCWJCSZREXCHZUNMXZ</span>
</span><span class='line'>
</span><span class='line'><span class="no">NXUCDRJXYYSMRTMEYIFZWDYVZVYFZUMRZCRWNZDZJJ</span>
</span><span class='line'>
</span><span class='line'><span class="no">XZWGCHSMRNMDHNCMFQCHZJMXJXWIFJYUCFWDJNZDIR</span>
</span></code></pre></td></tr></table></div></figure>


<p>这种密文的频率分析如下图：</p>

<p><img src="http://upload-images.jianshu.io/upload_images/1796624-3e73907eab25c8f3?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image" /></p>

<p>根据<a href="https://zh.wikipedia.org/wiki/%E5%AD%97%E6%AF%8D%E9%A2%91%E7%8E%87">英文字母出现的频率</a>排序统计，一般的排序是这样的e,t,a,o,I,n,s,h,r,d,l,u,c,m,f,w,y,p,v,b,g,k,j,q,x,z 而且一般英语文章中出现频率最高的的字母是e,这一点基本不会错的。</p>

<p>根据上图所示，字母Z出现的次数是20，远远高于其它密文字母，所以我们可以假设Z->e。其它出现至少10余次的官方字母是C,D,F,J,M,R,Y，我们希望这些字母对应的是</p>

<p>e t a o l n s h r中的一个子集，</p>

<p>我们现在假设了Z->e，现注意一下形如-Z, Z-的两字母组，我们发现出现这种类型的最一般的两字母组是DZ和ZW,各都出现了4次；NZ和ZU出现3次，RZ HZ XZ FZ ZR ZV ZC ZD ZJ各出现2次；又因ZW出现4次，而WZ一次也未出现，同时W比许多其它字母出现的次娄少，所以我们可以假设W->d，又因为DZ出现4次而ZD出现2次，故可猜测D是{r,s,t}中的任一个，具体是哪个还不清楚。</p>

<p>如上面猜测， Z->, D->d，再看看密文并注意到ZRW出现在密文的开始部分，RW后面也出现过，因为R在密文频繁地出现，而nd是一个常见的两字母组，所以我们可以假设R->n作为可能的情况，这样我们便有了如下的形式</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="o">------</span><span class="k">end</span><span class="o">---------</span><span class="n">e</span><span class="o">-----</span><span class="n">ned</span><span class="o">--</span><span class="n">e</span><span class="o">------------</span>
</span><span class='line'><span class="no">YIFQFMZRWQFYVECFMDZPCVMRZWNMDZVEJBTXCDDUMJ</span>
</span><span class='line'><span class="o">--------</span><span class="n">e</span><span class="o">----</span><span class="n">e</span><span class="o">---------</span><span class="n">n</span><span class="o">-</span><span class="n">d</span><span class="o">----</span><span class="n">en</span><span class="o">----</span><span class="n">e</span><span class="o">----</span><span class="n">e</span>
</span><span class='line'><span class="no">NDIFEFMDZCDMQZKCEYFCJMYRNCWJCSZREXCHZUNMXZ</span>
</span><span class='line'><span class="o">-</span><span class="n">e</span><span class="o">---</span><span class="n">n</span><span class="o">------</span><span class="n">n</span><span class="o">------</span><span class="n">ed</span><span class="o">-----</span><span class="n">e</span><span class="o">-</span><span class="n">e</span><span class="o">--</span><span class="n">ne</span><span class="o">-</span><span class="n">nd</span><span class="o">-</span><span class="n">e</span><span class="o">-</span><span class="n">e</span><span class="o">--</span>
</span><span class='line'><span class="no">NZUCDRJXYYSMRTMEYIFZWDYVZVYFZUMRZCRWNZDZJJ</span>
</span><span class='line'><span class="o">-</span><span class="n">ed</span><span class="o">-----</span><span class="n">n</span><span class="o">-----------</span><span class="n">e</span><span class="o">----</span><span class="n">ed</span><span class="o">-------</span><span class="n">d</span><span class="o">---</span><span class="n">e</span><span class="o">--</span><span class="n">n</span>
</span><span class='line'><span class="no">XZWGCHSMRNMDHNCMFQCHZJMXJZWIFJYUCFWDJNZDIR</span>
</span></code></pre></td></tr></table></div></figure>


<p>接下来我们可以试试N->h，因为NZ是一个常见的两字组而ZN不是一个常见的两字母组，如果这个猜测是正确的，则明文ne-ndhe很可能说明C->a，结合这些收市，我们又进一步有:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="o">------</span><span class="k">end</span><span class="o">-----</span><span class="n">a</span><span class="o">---</span><span class="n">e</span><span class="o">-</span><span class="n">a</span><span class="o">--</span><span class="n">nedh</span><span class="o">--</span><span class="n">e</span><span class="o">------</span><span class="n">a</span><span class="o">-----</span>
</span><span class='line'><span class="no">YIFQFMZRWQFYVECFMDZPCVMRZWNMDZVEJBTXCDDUMJ</span>
</span><span class='line'><span class="n">h</span><span class="o">-------</span><span class="n">ea</span><span class="o">---</span><span class="n">e</span><span class="o">-</span><span class="n">a</span><span class="o">---</span><span class="n">a</span><span class="o">----</span><span class="n">ehad</span><span class="o">-</span><span class="n">a</span><span class="o">-</span><span class="n">en</span><span class="o">-</span><span class="n">a</span><span class="o">-</span><span class="n">e</span><span class="o">-</span><span class="n">h</span><span class="o">--</span><span class="n">e</span>
</span><span class='line'><span class="no">NDIFEFMDZCDMQZKCEYFCJMYRNCWJCSZREXCHZUNMXZ</span>
</span><span class='line'><span class="n">he</span><span class="o">-</span><span class="n">a</span><span class="o">-</span><span class="n">n</span><span class="o">------</span><span class="n">n</span><span class="o">------</span><span class="n">ed</span><span class="o">---</span><span class="n">e</span><span class="o">---</span><span class="n">e</span><span class="o">--</span><span class="n">neandhe</span><span class="o">-</span><span class="n">e</span><span class="o">--</span>
</span><span class='line'><span class="no">NZUCDRJXYYSMRTMEYIFZWDYVZVYFZUMRZCRWNZDZJJ</span>
</span><span class='line'><span class="o">-</span><span class="n">ed</span><span class="o">-</span><span class="n">a</span><span class="o">---</span><span class="n">nh</span><span class="o">---</span><span class="n">ha</span><span class="o">---</span><span class="n">a</span><span class="o">-</span><span class="n">e</span><span class="o">----</span><span class="n">ed</span><span class="o">-----</span><span class="n">a</span><span class="o">-</span><span class="n">d</span><span class="o">--</span><span class="n">he</span><span class="o">--</span><span class="n">n</span>
</span><span class='line'><span class="no">XZWGCHSMRNMDHNCMFQCHZJMXJZWIFJYUCFWDJNZDIR</span>
</span></code></pre></td></tr></table></div></figure>


<p>现在考虑出现次数高的密文字母M,由前面分析，密文段RNM密钥成nh-，这说明h-是一个词的开头，所以M很可能是一个元音，因为已经使用了a和e,所以猜测M->{i或o}，因为ai是一个比ao出现次数更高的明文组，所以首先猜测M->I，这样就有：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="o">-----</span><span class="n">iend</span><span class="o">-----</span><span class="n">a</span><span class="o">-</span><span class="n">i</span><span class="o">-</span><span class="n">e</span><span class="o">-</span><span class="n">a</span><span class="o">-</span><span class="n">inedh</span><span class="o">--</span><span class="n">e</span><span class="o">------</span><span class="n">a</span><span class="o">---</span><span class="n">i</span><span class="o">-</span>
</span><span class='line'><span class="no">YIFQFMZRWQFYVECFMDZPCVMRZWNMDZVEJBTXCDDUMJ</span>
</span><span class='line'><span class="n">h</span><span class="o">-----</span><span class="n">i</span><span class="o">-</span><span class="n">ea</span><span class="o">-</span><span class="n">i</span><span class="o">-</span><span class="n">e</span><span class="o">-</span><span class="n">a</span><span class="o">---</span><span class="n">a</span><span class="o">-</span><span class="n">i</span><span class="o">-</span><span class="n">nhad</span><span class="o">-</span><span class="n">a</span><span class="o">-</span><span class="n">en</span><span class="o">--</span><span class="n">a</span><span class="o">-</span><span class="n">e</span><span class="o">-</span><span class="n">hi</span><span class="o">-</span><span class="n">e</span>
</span><span class='line'><span class="no">NDIFEFMDZCDMQZKCEYFCJMYRNCWJCSZREXCHZUNMXZ</span>
</span><span class='line'><span class="n">he</span><span class="o">-</span><span class="n">a</span><span class="o">-</span><span class="n">n</span><span class="o">-----</span><span class="k">in</span><span class="o">-</span><span class="n">i</span><span class="o">----</span><span class="n">ed</span><span class="o">---</span><span class="n">e</span><span class="o">---</span><span class="n">e</span><span class="o">-</span><span class="n">ineandhe</span><span class="o">--</span><span class="n">e</span><span class="o">-</span>
</span><span class='line'><span class="no">NZUCDRJXYYSMRTMEYIFZWDYVZVYFZUMRZCRWNZDZJJ</span>
</span><span class='line'><span class="o">-</span><span class="n">ed</span><span class="o">-</span><span class="n">a</span><span class="o">--</span><span class="n">inhi</span><span class="o">--</span><span class="n">hai</span><span class="o">--</span><span class="n">a</span><span class="o">-</span><span class="n">e</span><span class="o">-</span><span class="n">i</span><span class="o">---</span><span class="n">ed</span><span class="o">----</span><span class="n">a</span><span class="o">--</span><span class="n">d</span><span class="o">-</span><span class="n">he</span><span class="o">--</span><span class="n">n</span>
</span><span class='line'><span class="no">XZWGCHSMRNMDHNCMFQCHZJMXJZWIFJYUCFWDJNZDIR</span>
</span></code></pre></td></tr></table></div></figure>


<p>下面需要确定明文o对应的密文，因为为是一个经常出现的字母，所以我们猜测相应的密文字母是D F J Y 中的一个，Y似乎最有可能，否则将得到长元音，即从CFM或CJM中得到aoi,因此假设Y->o。</p>

<p>剩下密文字母中三个最高频率的字母是D F J,我们猜测他们以某种次序解密成r s t， 三字母NMD两次出现说明很可能D->s,对应的明文三字母组为his，HNCMF可能是chair的加密，说明F->r,H->c，同时排除J->t，于是我们有了：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">o</span><span class="o">-</span><span class="n">r</span><span class="o">-</span><span class="n">riend</span><span class="o">-</span><span class="n">ro</span><span class="o">--</span><span class="n">arise</span><span class="o">-</span><span class="n">a</span><span class="o">-</span><span class="n">inedhise</span><span class="o">--</span><span class="n">t</span><span class="o">---</span><span class="n">ass</span><span class="o">-</span><span class="n">it</span>
</span><span class='line'><span class="no">YIFQFMZRWQFYVECFMDZPCVMRZWNMDZVEJBTXCDDUMJ</span>
</span><span class='line'><span class="n">hs</span><span class="o">-</span><span class="n">r</span><span class="o">-</span><span class="n">riseasi</span><span class="o">-</span><span class="n">e</span><span class="o">-</span><span class="n">a</span><span class="o">-</span><span class="n">orationhadta</span><span class="o">-</span><span class="n">en</span><span class="o">--</span><span class="n">ace</span><span class="o">-</span><span class="n">hi</span><span class="o">-</span><span class="n">e</span>
</span><span class='line'><span class="no">NDIFEFMDZCDMQZKCEYFCJMYRNCWJCSZREXCHZUNMXZ</span>
</span><span class='line'><span class="n">he</span><span class="o">-</span><span class="n">asnt</span><span class="o">-</span><span class="n">oo</span><span class="o">-</span><span class="k">in</span><span class="o">-</span><span class="n">i</span><span class="o">-</span><span class="n">o</span><span class="o">-</span><span class="n">redso</span><span class="o">-</span><span class="n">e</span><span class="o">-</span><span class="n">ore</span><span class="o">-</span><span class="n">ineandhesett</span>
</span><span class='line'><span class="no">NZUCDRJXYYSMRTMEYIFZWDYVZVYFZUMRZCRWNZDZJJ</span>
</span><span class='line'><span class="o">-</span><span class="n">ed</span><span class="o">-</span><span class="n">ac</span><span class="o">-</span><span class="n">inhischair</span><span class="o">-</span><span class="n">acet</span><span class="o">-</span><span class="n">i</span><span class="o">-</span><span class="n">ted</span><span class="o">-</span><span class="n">to</span><span class="o">-</span><span class="n">ardsthes</span><span class="o">-</span><span class="n">n</span>
</span><span class='line'><span class="no">XZWGCHSMRNMDHNCMFQCHZJMXJZWIFJYUCFWDJNZDIR</span>
</span></code></pre></td></tr></table></div></figure>


<p>有了上面的提示，就很容易确定出明文，解密明文如下</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Our</span> <span class="n">friend</span> <span class="n">from</span> <span class="n">paris</span> <span class="n">examined</span> <span class="n">his</span> <span class="n">empty</span> <span class="n">glass</span> <span class="n">with</span> <span class="n">surprise</span><span class="p">,</span> <span class="n">as</span> <span class="n">ifevaporation</span> <span class="n">has</span> <span class="n">taken</span> <span class="n">place</span> <span class="k">while</span> <span class="n">he</span> <span class="n">wasn</span><span class="err">’</span><span class="n">t</span><span class="err"> </span><span class="n">looking</span><span class="p">,</span> <span class="n">I</span> <span class="n">poured</span> <span class="n">some</span> <span class="n">more</span> <span class="n">wine</span> <span class="ow">and</span> <span class="n">hesettled</span> <span class="n">back</span> <span class="k">in</span> <span class="n">his</span> <span class="n">chair</span><span class="p">,</span><span class="n">face</span> <span class="n">tilted</span> <span class="n">up</span> <span class="n">towards</span> <span class="n">the</span> <span class="n">sun</span><span class="o">.</span>
</span></code></pre></td></tr></table></div></figure>


<h3>参考资料</h3>

<p>【密码学原理与实践（第三版）】</p>

<p>【图解密码技术】</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[密码学(一)之移位密码(恺撒密码)]]></title>
    <link href="http://xuyao.club/blog/2018/07/13/cryptography-of-shift-cipher/"/>
    <updated>2018-07-13T14:03:33+08:00</updated>
    <id>http://xuyao.club/blog/2018/07/13/cryptography-of-shift-cipher</id>
    <content type="html"><![CDATA[<h3>前言</h3>

<p>   密码学的基本目的是使得两个在不安全的信道上进行安全的通信，在计算机网络中，现假设有两个人Alice和Bob，Alice想发送消息给Bob，告诉他明天凌晨2点毒贩将在4号码头进行交易，请Bob配合缉毒。这里Alice有一个麻烦就是他怕在信息传输中可能会被敌人Oscar监听，甚至篡改消息内容，导致整个计划失败，Bob也对Alice发过来的消息有疑虑，不知道消息是否为Alice本人所发，消息内容是否真实等等。<br/>
   <!-- more --></p>

<p> 这里密码学的重要性就体现出来了，假设Alice事先和Bob商量好一个密钥（key）,Alice通过密钥将明文（plaintext）加密成密文，在网络中传输，Bob收到Alice传过来的密文（ciphertext），用事先商量好的密钥进行解密，得到明文，而敌人即使监听到Alice发送的消息，也是加密过的密文，由于不知道密钥，所以无法知道真实的明文，整个过程如下。
<img src="https://upload-images.jianshu.io/upload_images/1796624-95050e2fc8412a32.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" /></p>

<h3>移位密码（Shift Cipher）、恺撒密码(Caesar Cipher)</h3>

<p>移位密码是古典密码学中最早，最简单的一种加、解密码方法，最早可追溯至古罗马时代，尤利乌斯:恺撒曾经使用过此密码。</p>

<p>移位密码是通过将明文中所使用的字母按照一定的字数进行“平移”来加密，为了简化内容，在这里我们只使用英文字母作为示例，我们用小写字母(a,b,c,d…)来表示明文，用大写字母（A,B,C,D…）来表示密文。</p>

<p>最早期时，一般将字母平移3位，也就是a->D，b->E，c->F,
这种最早时平移3位是叫<strong>恺撒密码(Caesar Cipher)</strong>，后来经过推广，平移位数也不一定是3位，可以是其它任何整数位，这种又叫<strong>移位密码（Shift Cipher）</strong>，可以知道，恺撒密码是移位密码的一个特例（key=3时），下面是恺撒密码平移的工作方式<br/>
<img src="https://upload-images.jianshu.io/upload_images/1796624-e1fa042fd62a2c56.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" /></p>

<h3>移位密码的加密</h3>

<p> 使用移位密码可以用来加密普通的英文句子，但是我们要建立英文字母和模26剩余之间一一对应关系，如A->0，B->1,…Z->25。其列表如下：<br/>
<img src="https://upload-images.jianshu.io/upload_images/1796624-0dbef7eedef6d7dc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="image.png" /><br/>
现假设我们有明文P=china，密钥K=3, 现要将其加密，根据上表，将字符P中的每个字母平移3位，得到如下情况:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">c</span><span class="o">-&gt;</span><span class="n">F</span>
</span><span class='line'><span class="n">h</span><span class="o">-&gt;</span><span class="n">K</span>
</span><span class='line'><span class="n">i</span><span class="o">-&gt;</span><span class="n">L</span>
</span><span class='line'><span class="n">n</span><span class="o">-&gt;</span><span class="n">Q</span>
</span><span class='line'><span class="n">a</span><span class="o">-&gt;</span><span class="n">D</span>
</span></code></pre></td></tr></table></div></figure>


<p>至此，明文china就被转换成了密文FKLQD，<br/>
具体用程序算法可归纳如下:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">a</span><span class="err">，首先将明文中的字母按照上表对应成相应的数字：</span>
</span><span class='line'>   <span class="mi">2</span> <span class="mi">7</span> <span class="mi">8</span> <span class="mi">13</span> <span class="mi">0</span>
</span><span class='line'><span class="n">b</span><span class="err">，再将上面的数字与密钥</span><span class="n">K</span><span class="o">=</span><span class="mi">3</span><span class="err">相加：</span>
</span><span class='line'>   <span class="mi">5</span> <span class="mi">10</span> <span class="mi">11</span> <span class="mi">16</span> <span class="mi">3</span>
</span><span class='line'><span class="n">c</span><span class="err">，再对各个数字取模</span><span class="mi">26</span><span class="err">运算，可得：</span>
</span><span class='line'>   <span class="mi">5</span> <span class="mi">10</span> <span class="mi">11</span> <span class="mi">16</span> <span class="mi">3</span>
</span><span class='line'><span class="n">d</span><span class="err">，最后将各数字转化为字母即可得密文</span>
</span><span class='line'>   <span class="n">F</span>  <span class="n">K</span>  <span class="n">L</span>  <span class="n">Q</span>  <span class="n">D</span>
</span></code></pre></td></tr></table></div></figure>


<p>具体代码可参考这里
<a href="https://github.com/xuyao91/cryptography/blob/master/caesar/caesar.rb#L10">https://github.com/xuyao91/cryptography/blob/master/caesar/caesar.rb#L10</a></p>

<h3>移位密码的解密</h3>

<p>移位密码的解密也非常简单，只要使用加密时用的密钥进行反向平移操作，刚来的例子只要将密文反向平移3位就行，可得到如下：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">F</span><span class="o">-&gt;</span><span class="n">c</span>
</span><span class='line'><span class="n">K</span><span class="o">-&gt;</span><span class="n">h</span>
</span><span class='line'><span class="n">L</span><span class="o">-&gt;</span><span class="n">i</span>
</span><span class='line'><span class="n">Q</span><span class="o">-&gt;</span><span class="n">n</span>
</span><span class='line'><span class="n">D</span><span class="o">-&gt;</span><span class="n">a</span>
</span></code></pre></td></tr></table></div></figure>


<p>具体程序的算法其实就是加密的反向操作，如下：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">a</span><span class="err">，</span> <span class="err">将密文转化成对应的字母</span>
</span><span class='line'>    <span class="mi">5</span> <span class="mi">10</span> <span class="mi">11</span> <span class="mi">16</span> <span class="mi">3</span>
</span><span class='line'><span class="n">b</span><span class="err">，</span> <span class="err">将各数字减去密钥</span><span class="n">K</span><span class="o">=</span><span class="mi">3</span><span class="err">，得到如下数字</span>
</span><span class='line'>    <span class="mi">2</span> <span class="mi">7</span> <span class="mi">8</span> <span class="mi">13</span> <span class="mi">0</span>
</span><span class='line'><span class="n">c</span><span class="err">，</span> <span class="err">再对各个数字取模</span><span class="mi">26</span><span class="err">运算，得：</span>
</span><span class='line'>    <span class="mi">2</span> <span class="mi">7</span> <span class="mi">8</span> <span class="mi">13</span> <span class="mi">0</span>
</span><span class='line'><span class="n">d</span><span class="err">，</span> <span class="err">最后将数字转化成字母得</span>
</span><span class='line'>    <span class="n">c</span> <span class="n">h</span> <span class="n">i</span>  <span class="n">n</span> <span class="n">a</span>
</span></code></pre></td></tr></table></div></figure>


<p>具体代码可参考这里：
<a href="https://github.com/xuyao91/cryptography/blob/master/caesar/caesar.rb#L18">https://github.com/xuyao91/cryptography/blob/master/caesar/caesar.rb#L18</a></p>

<h3>移位密码的暴力破解</h3>

<p>通过上面的例子可以知道，我们只要拿到的密钥K，就可以密文解密，那么有没有不用密钥就可以解密的呢，在移位密码中，密钥就是字母平移的位数，因为因为字母表里只有26个字母（0-25），所以加密的密钥一共就是0-25之间的26个数字，我们可以把26个数字全部当作密钥试一次，解密出来其中有一个明文肯定是对的。</p>

<p>像这种将所有可能的密钥全部尝试一遍的，我们叫<strong>暴力破解(brute-force attack)</strong>，这种方法本质是在所有的密钥中找出正确的那一个，因此又称为<strong>穷举搜索（exhaustive search）</strong>。</p>

<p>可以将上面的例子通过暴力破解试一下，密钥从0开始，一直试到25，得到如下效果：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">0</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">fklqd</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">1</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">ejkpc</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">2</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">dijob</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">3</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">china</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">4</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">bghmz</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">5</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">afgly</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">6</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">zefkx</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">7</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">ydejw</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">8</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">xcdiv</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">9</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">wbchu</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">10</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">vabgt</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">11</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">uzafs</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">12</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">tyzer</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">13</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">sxydq</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">14</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">rwxcp</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">15</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">qvwbo</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">16</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">puvan</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">17</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">otuzm</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">18</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">nstyl</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">19</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">mrsxk</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">20</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">lqrwj</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">21</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">kpqvi</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">22</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">jopuh</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">23</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">inotg</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">24</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">hmnsf</span>
</span><span class='line'><span class="no">FKLQD</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">25</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">glmre</span>
</span></code></pre></td></tr></table></div></figure>


<p>可以知道，其实在试到第3次的时候，明文就被试出来了
代码可以参考这里
<a href="https://github.com/xuyao91/cryptography/blob/master/caesar/caesar.rb#L26">https://github.com/xuyao91/cryptography/blob/master/caesar/caesar.rb#L26</a></p>

<h3>脚本示例</h3>

<p>  我们用脚本试一下上面所说的各种方法，脚本代码在这里</p>

<p><a href="https://github.com/xuyao91/cryptography/blob/master/caesar/caesar.rb">https://github.com/xuyao91/cryptography/blob/master/caesar/caesar.rb</a></p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1">#明文是 I am peter, I love china， 密钥是6</span>
</span><span class='line'><span class="n">message</span> <span class="o">=</span> <span class="s2">&quot;iampeterxuilovechina&quot;</span>
</span><span class='line'><span class="n">caesar</span> <span class="o">=</span> <span class="no">Caesar</span><span class="o">.</span><span class="n">new</span> <span class="mi">6</span>
</span><span class='line'>
</span><span class='line'><span class="c1">#调用encoder方法加密出密文</span>
</span><span class='line'><span class="n">cipher</span> <span class="o">=</span> <span class="n">caesar</span><span class="o">.</span><span class="n">encoder</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="no">OGSVKZKXDAORUBKINOTG</span>
</span><span class='line'>
</span><span class='line'><span class="c1">#调用decoder方法解密出明文</span>
</span><span class='line'><span class="n">caesar</span><span class="o">.</span><span class="n">decoder</span><span class="p">(</span><span class="n">cipher</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">iampeterxuilovechina</span>
</span><span class='line'>
</span><span class='line'><span class="c1">#暴力破解</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">0</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">ogsvkzkxdaorubkinotg</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">1</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">nfrujyjwcznqtajhmnsf</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">2</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">meqtixivbympsziglmre</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">3</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">ldpshwhuaxloryhfklqd</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">4</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">kcorgvgtzwknqxgejkpc</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">5</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">jbnqfufsyvjmpwfdijob</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">6</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">iampeterxuilovechina</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">7</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">hzlodsdqwthknudbghmz</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">8</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">gykncrcpvsgjmtcafgly</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">9</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">fxjmbqbourfilsbzefkx</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">10</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">ewilapantqehkraydejw</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">11</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">dvhkzozmspdgjqzxcdiv</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">12</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">cugjynylrocfipywbchu</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">13</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">btfixmxkqnbehoxvabgt</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">14</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">asehwlwjpmadgnwuzafs</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">15</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">zrdgvkviolzcfmvtyzer</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">16</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">yqcfujuhnkybelusxydq</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">17</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">xpbetitgmjxadktrwxcp</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">18</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">woadshsfliwzcjsqvwbo</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">19</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">vnzcrgrekhvybirpuvan</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">20</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">umybqfqdjguxahqotuzm</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">21</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">tlxapepciftwzgpnstyl</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">22</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">skwzodobhesvyfomrsxk</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">23</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">rjvyncnagdruxenlqrwj</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">24</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">qiuxmbmzfcqtwdmkpqvi</span>
</span><span class='line'><span class="no">OGSVKZKXDAORUBKINOTG</span> <span class="o">-&gt;</span> <span class="err">第</span><span class="mi">25</span><span class="err">次破解</span> <span class="o">-&gt;</span> <span class="n">phtwlalyebpsvcljopuh</span>
</span></code></pre></td></tr></table></div></figure>


<p>可以知道，移位密码其实是很弱的，我们可以很容易将他破解出来，但是在古代那会还是挺有用的。</p>

<h3>参考资料</h3>

<p>【密码学原理与实践（第三版）】</p>

<p>【图解密码技术】</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[如何理解RESTful]]></title>
    <link href="http://xuyao.club/blog/2018/03/12/how-to-understand-the-restful-router/"/>
    <updated>2018-03-12T11:07:56+08:00</updated>
    <id>http://xuyao.club/blog/2018/03/12/how-to-understand-the-restful-router</id>
    <content type="html"><![CDATA[<h3>什么是REST</h3>

<p>&emsp;&emsp;REST的全称是：Representational State Transfer,直接翻译过来就是：表现层状态转移，表现层的意思就是资源, 这个词语读着比较难理解，网上有一种叫法比较容易理解，叫：URL定位资源，用HTTP动词（GET,POST,PUT,DELETE）描述操作。很简洁，就是看url就知道这个路由是什么了，然后看http的动词method就明白要做什么了，最后看他的 status code就知道返回结果了。REST最大的几个特点为：资源、统一接口、URI和无状态。</p>

<h3>RESTful架构</h3>

<p>&emsp;&emsp;RESTful 是现在比较流行的一种设计风格，它提供了一组设计原则和约束条件，主要用于客户端与服务器的交互。RESTful架构更简洁，更有层次，更易于实现缓存等机制。<br/>
&emsp;&emsp;记得刚工作那会，代码写的比较烂，比如说要写增加商品的路由，会写成下面这样,从RESTful角度来说，这样写其实已经违背了他统一接口和对URI的意义的原则</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">POST</span> <span class="sr">/create_product</span>
</span></code></pre></td></tr></table></div></figure>


<!-- more -->


<p></p>

<ul>
<li>首先URI上最好不要有create,pudate,get等这种动词，URI上只要描述他是什么东西就行了，且以复数最好吧，比如说products,users,orders等等</li>
<li>如果接口是增加，删除，更新等操作可以在请求方式上来表现，常见的有以下这些：<br/>
GET &emsp;&emsp;     ->获取一个资源 <br/>
POST &emsp;&emsp;    ->添加一个资源 <br/>
PUT &emsp;&emsp;     ->修改一个资源 <br/>
DELETE &emsp;&emsp;  ->删除一个资源 <br/>
比如说要增加一个商品，可以写成这样</li>
</ul>


<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1">#TODO 增加商品</span>
</span><span class='line'><span class="no">POST</span> <span class="sr">/products</span>
</span><span class='line'>
</span><span class='line'><span class="sr">#TODO 获取商品列表</span>
</span><span class='line'><span class="sr">GET /</span><span class="n">products</span>
</span><span class='line'>
</span><span class='line'><span class="c1">#TODO 获取某个单个商品</span>
</span><span class='line'><span class="no">GET</span> <span class="sr">/products/</span><span class="mi">1</span>
</span><span class='line'>
</span><span class='line'><span class="c1">#TODO 更新某个商品</span>
</span><span class='line'><span class="no">PUT</span> <span class="sr">/products/</span><span class="mi">1</span>
</span><span class='line'>
</span><span class='line'><span class="c1">#TODO 删除某个商品</span>
</span><span class='line'><span class="no">DELETE</span> <span class="sr">/products/</span><span class="mi">1</span>
</span></code></pre></td></tr></table></div></figure>


<p> <br/>
上面这样写明显很简洁，虽然有些URI是相同的，但并不会存在歧义，你只要看他的http method就知道是做什么操作的了，而且这样明显更有层次感，如果是嵌套路由的话，层次感就更明显了。<br/>
以上是一些人个见解，下面是网上摘来的一些比较专业的述语</p>

<h3>RESTful详解</h3>

<h4>1.1 资源与URI</h4>

<p>这里以github网站为例，给出一些还算不错的URI：</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="ss">https</span><span class="p">:</span><span class="sr">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">git</span>
</span><span class='line'><span class="ss">https</span><span class="p">:</span><span class="sr">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">git</span><span class="o">/</span><span class="n">git</span><span class="o">/</span><span class="n">blob</span><span class="o">/</span><span class="n">master</span><span class="o">/</span><span class="n">block</span><span class="o">-</span><span class="n">sha1</span><span class="o">/</span><span class="n">sha1</span><span class="o">.</span><span class="n">h</span>
</span><span class='line'><span class="ss">https</span><span class="p">:</span><span class="sr">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">git</span><span class="o">/</span><span class="n">git</span><span class="o">/</span><span class="n">pulls</span>
</span><span class='line'><span class="ss">https</span><span class="p">:</span><span class="sr">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">git</span><span class="o">/</span><span class="n">git</span><span class="o">/</span><span class="n">pulls?state</span><span class="o">=</span><span class="n">closed</span>
</span></code></pre></td></tr></table></div></figure>


<p>关于URI设计技巧:</p>

<ul>
<li>使用 _ 或 - 来让URI可读性更好，例如<a href="http://www.github.com/blog/translate-reward-plan%E3%80%82">http://www.github.com/blog/translate-reward-plan%E3%80%82</a></li>
<li>使用 / 来表示资源的层级关系，例如上面的/git/git/blob/master/block-sha1/sha1.h</li>
<li>使用 ? 用来过滤资源，例如/git/pulls?state=closed用来表示git项目的所有推入请求中已经关闭的请求。</li>
<li>使用,或;表示同级资源关系，例如/git/sha1/compare/ef7b53d18;bd638e8c1</li>
</ul>


<h4>1.2 统一资源接口</h4>

<p>RESTful架构应该遵循统一接口原则，统一接口包含了一组受限的预定义的操作，所有资源的访问接口应该使用标准的HTTP方法如GET，PUT，POST，DELETE，并遵循这些方法的语义。</p>

<p>如果按照HTTP方法的语义来暴露资源，那么接口将会拥有安全性和幂等性的特性，例如GET和HEAD请求都是安全的， 无论请求多少次，都不会改变服务器状态。而GET、HEAD、PUT和DELETE请求都是幂等的，无论对资源操作多少次， 结果总是一样的，后面的请求并不会产生比第一次更多的影响。
下面列出了GET，DELETE，PUT和POST的典型用法:</p>

<h6>GET</h6>

<p>&emsp;&emsp;安全且幂等 获取表示 变更时获取表示（缓存） 200（OK） - 表示已在响应中发出 204（无内容） - 资源有空表示 301（Moved Permanently） - 资源的URI已被更新 303（See Other） - 其他（如，负载均衡） 304（not modified）- 资源未更改（缓存） 400 （bad request）- 指代坏请求（如，参数错误） 404 （not found）- 资源不存在 406 （not acceptable）- 服务端不支持所需表示 500 （internal server error）- 通用错误响应 503 （Service Unavailable）- 服务端当前无法处理请求</p>

<h5>POST</h5>

<p>&emsp;&emsp;不安全且不幂等 使用服务端管理的（自动产生）的实例号创建资源 创建子资源 部分更新资源 如果没有被修改，则不过更新资源（乐观锁） 200（OK）- 如果现有资源已被更改 201（created）- 如果新资源被创建 202（accepted）- 已接受处理请求但尚未完成（异步处理） 301（Moved Permanently）- 资源的URI被更新 303（See Other）- 其他（如，负载均衡） 400（bad request）- 指代坏请求 404 （not found）- 资源不存在 406 （not acceptable）- 服务端不支持所需表示 409 （conflict）- 通用冲突 412 （Precondition Failed）- 前置条件失败（如执行条件更新时的冲突） 415 （unsupported media type）- 接受到的表示不受支持 500 （internal server error）- 通用错误响应 503 （Service Unavailable）- 服务当前无法处理请求</p>

<h5>PUT</h5>

<p>&emsp;&emsp;不安全但幂等 用客户端管理的实例号创建一个资源 通过替换的方式更新资源 如果未被修改，则更新资源（乐观锁） 200 （OK）- 如果已存在资源被更改 201 （created）- 如果新资源被创建 301（Moved Permanently）- 资源的URI已更改 303 （See Other）- 其他（如，负载均衡 ） 400 （bad request）- 指代坏请求 404 （not found）- 资源不存在 406 （not acceptable）- 服务端不支持所需表示 409 （conflict）- 通用冲突 412 （Precondition Failed）- 前置条件失败（如执行条件更新时的冲突） 415 （unsupported media type）- 接受到的表示不受支持 500 （internal server error）- 通用错误响应 503 （Service Unavailable）- 服务当前无法处理请求</p>

<h5>DELETE</h5>

<p>&emsp;&emsp;不安全但幂等 删除资源 200 （OK）- 资源已被删除 301 （Moved Permanently）- 资源的URI已更改 303 （See Other）- 其他，如负载均衡 400 （bad request）- 指代坏请求 404 （not found）- 资源不存在 409 （conflict）- 通用冲突 500 （internal server error）- 通用错误响应 503 （Service Unavailable）- 服务端当前无法处理请求</p>

<p>&emsp;&emsp;接下来再按一些实践中的常见问题
POST和PUT在创建资源的区别：所创建的资源的名称(URI)是否由客户端决定。 例如为为博客增加一个android的分类，生成的路径就是分类名/categories/android，那么就可以采用PUT方法。
客户端不一定都支持这些HTTP方法：较古老的基于浏览器的客户端，只能支持GET和POST两种方法。妥协的解决方法，通过隐藏参数_method=DELETE来传递真实的请求方法等措施来规避。
统一资源接口对URI的意义：统一资源接口要求使用标准的HTTP方法对资源进行操作，所以URI只应该来表示资源的名称，而不应该包括资源的操作，如下是一些不符合统一接口要求的URI:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">GET</span> <span class="sr">/getUser/</span><span class="mi">1</span>
</span><span class='line'><span class="no">POST</span> <span class="sr">/createUser  </span>
</span><span class='line'><span class="sr">PUT /u</span><span class="n">pdateUser</span><span class="o">/</span><span class="mi">1</span>
</span><span class='line'><span class="no">DELETE</span> <span class="sr">/deleteUser/</span><span class="mi">1</span>
</span><span class='line'><span class="err">正确写法应该是</span> <span class="sr">/User/</span><span class="mi">1</span>
</span></code></pre></td></tr></table></div></figure>


<p>不应该包含动词，具体的动作由请求方法来体现。</p>

<h5>1.3 资源的表述</h5>

<p>&emsp;&emsp;资源的表述是指对资源在特定时刻的状态的描述，客户端通过HTTP方法可以获取资源，更准确说是资源的表述而已。 资源在外界的具体呈现，可以有多种表述形式，在客户端和服务端之间传送的也是资源的表述，而不是资源本身。 例如文本资源可以采用html、xml、json等格式，图片可以使用PNG或JPG展现出来。</p>

<p>&emsp;&emsp;资源的表述包括数据和描述数据的元数据，例如，HTTP头”Content-Type” 就是这样一个元数据属性。通过HTTP内容协商，客户端可以通过Accept头请求一种特定格式的表述，服务端则通过Content-Type告诉客户端资源的表述形式。</p>

<h5>1.4 资源的链接</h5>

<p>&emsp;&emsp;REST是使用标准的HTTP方法来操作资源的，但仅仅因此就理解成带CURD的Web数据库架构就太过于简单了。这种反模式忽略了一个核心概念：”超媒体即应用状态引擎”。 超媒体是什么?当你浏览Web网页时，从一个连接跳到一个页面，再从另一个连接跳到另外一个页面，就是利用了超媒体的概念：把一个个把资源链接起来.
&emsp;&emsp;要达到这个目的，就要求在表述格式里边加入链接来引导客户端。在《RESTful Web Services》一书中，作者把这种具有链接的特性成为连通性。下面我们具体来看一些例子。</p>

<h5>1.5 状态的转移</h5>

<p>&emsp;&emsp;REST原则中的无状态通信原则，并不是说客户端应用不能有状态，而是指服务端不应该保存客户端状态。</p>
]]></content>
  </entry>
  
</feed>
