原文链接:http://www.lotushy.com/?p=115

数据结构

在任意给定时刻,一个节点总是连接到多个其他节点。默认情况下,一个节点连接到8个其他节点(链出),并允许多达125个链入节点连接进来。

相关常量定义在net.h文件中。

节点集合则由全局变量vNodes维护。

CNode用于表示一个节点。

CNode包含许多属性,其中大部分属性都与底层链路(如套接字,字节流等)有关。

CNode的关键属性如下:

  • nServices: 通常被称为“服务位”。这是一个bitmap数据结构,用于表示peer提供的服务种类。具体种类如下。

    • NODE_NONE: 初值
    • NODE_NETWORK: 全节点。SPV节点和其他类型的轻节点不设置该标识。
    • NODE_GETUTXO: 该节点能够响应getutxo协议请求。Bitcoin Core节点不支持此功能。此功能由一个由Bitcoin XT支持。BIP64
    • NODE_BLOOM:
    • NODE_WITNESS: 表示可以向节点询问块和交易,包括见证数据。应该是只支持隔离见证。
    • NODE_XTHIN: 表示节点支持Xtreme Thinblocks
    • NODE_NETWORK_LIMITED: 表示节点仅支持最近的288年区块(即两天的数据)BIP159
  • fClient: 表示节点是否是SPV节点

  • fWhiteListed: 是否是白名单节点。如果是的话,该节点不会因为的行为被屏避掉。

  • vSendMsg: 队列中待发送的消息队列

  • vRecvMsg: 我们从Peer接收到的消息队列

节点发现和节点连接

地址管理

地址管理器用于管理节点的IP地址和端口。(见addrman.h)

设计目标:

  • 将地址表保存在内存中,并将整个表异步转储到peers.dat。
  • 确保没有(本地化的)攻击者可以用它的节点/地址填充整个表格。

为此:

  • 地址以Bucket的方式组织,即地址被放到桶里。
    • 尚未尝试过的地址进入1024个“new”桶。
    • 已知可访问的节点地址进入256个“tried”桶。
      • 每个地址范围随机选择8个桶
      • 根据完整地址从实际存储桶中选择实际存储桶。
      • 当为一个完整的桶添加一个新的好地址时,一个随机选择的entry(偏向于最近尝试过的)会被弹出,回到“新”桶。
    • 分组选择基于密码散列,使用随机生成的256位密钥,这不应该被攻击者观察到。
    • 多个索引用于提升性能。

** 时间戳 **

地址管理器也要持续跟踪每个节点的最近活跃情况。时间戳仅在一个地址上更新,并且在时间戳超过20分钟时保存到数据库。 通过理解时间戳的作用,将更加清楚的理解为什么要保持时间戳。

节点发现

节点发现从链路层来讲,就是发现一个节点的IP地址和端口号。有多种方式:

  • 地址数据库,即peers.dat文件
    • 在节点启动时读入并加载到节点管理器中。该方法在节点首次运行时是不支持的。因为peers.dat文件还不存在。
  • 用户指定(--addnode, --connect)
  • DNS种子(DNS seeding)
    • 仅当peers.dat文件为空时,DNS种子才会被使用。
    • 默认DNS种子有6个:seed.bitcoin.sipa.be, dnsseed.bluematt.me, dnsseed.bitcoin.dashjr.org, seed.bitcoinstats.com, seed.bitcoin.jonasschnelli.ch, seed.btc.petertodd.org
  • 硬编码的种子
    • 如果DNS seeding失败,客户端使用硬编码的种子。[chainparamsseeds.h] 这些地址仅用作最后的手段。理想情况是尽快远离种子节点,以避免过载这些节点。DNS种子和硬编码的种子的时间戳均为0,这样可以避免此类地址被广播到网络中或响应getaddr
  • 从其他Peer获取(getaddraddr消息)
    • 节点间通过getaddraddr交换IP地址信息。
    • 但是,“addr”消息也可能会不请自来,因为节点在以下情况时无偿地发布地址:
      • 当节点转发地址时
      • 周期性广播节点自己的地址(每24小时)
      • 当连接建立时(响应version消息时带回)
    • 节点发送getaddr消息的时机
      • 在响应version消息,并且节点自身的地址量小于1000时。
    • 当接收到addr时:
      • 发送消息的节点版本太老,并且我们已经有1000个节点地址了,该消息被忽略。
      • 如果节点是当前版本,并且尝试向我们发送超过1000个节点地址,则该节点会被惩罚。
      • 如果该地址24小时内已经发现,并且当前时间戳超过60分种,则时间戳更新为60分种。
      • 如果该地址24小时内没有出现过,而时间戳是24小时之前,则更新为24小时。
    • 当响应getaddr消息时:
      • 该节点计算出在过去3个小时内有多少个地址有时间戳。
      • 它发送这些地址,但如果有超过2500个地址,它随机选择2500。
      • 它清除我们认为远程节点所拥有的地址列表,这将触发发送到节点的刷新。 请参阅SendMessages。
    • 地址中继:
      • 一旦新地址被添加
        • 地址的时间戳在10分钟之内
        • addr消息包括10个地址或少一些
        • fGetAddr==false
        • 该地址是可路由的
        • 满足以上条件,则新地址会被随机的发送出去

节点连接

节点链接由线程ThreadOpenConnections管理。它负责选择可用的地址,建立链接并在适当的时候释放链接。

而inbound链接则由ThreadSocketHandler负责处理[ThreadMessageHandler]。

对于inbound链接,系统通过select执行IO操作。所以,其支持的inbound数量不会太多,目前,是125个。

插口(Sockets)和消息

Socket线程 (net.cpp)

消息线程

ProcessMessages (net_processing.cpp)

ProcessMessages是net_processing.cpp中的处理和验证交易和区块等相关代码代码的入口点,同时它也处理getaddr, addr等比特币协议相关的消息。该方法主要完成消息的复制并调用ProcessMessage处理消息。

ProcessMessage基本上是一个大型的“开关”,它根据消息类型[NetMsgType]来采取行动。

消息类型列表如下[protocol.cpp]:

namespace NetMsgType {
const char *VERSION="version";
const char *VERACK="verack";
const char *ADDR="addr";
const char *INV="inv";
const char *GETDATA="getdata";
const char *MERKLEBLOCK="merkleblock";
const char *GETBLOCKS="getblocks";
const char *GETHEADERS="getheaders";
const char *TX="tx";
const char *HEADERS="headers";
const char *BLOCK="block";
const char *GETADDR="getaddr";
const char *MEMPOOL="mempool";
const char *PING="ping";
const char *PONG="pong";
const char *NOTFOUND="notfound";
const char *FILTERLOAD="filterload";
const char *FILTERADD="filteradd";
const char *FILTERCLEAR="filterclear";
const char *REJECT="reject";
const char *SENDHEADERS="sendheaders";
const char *FEEFILTER="feefilter";
const char *SENDCMPCT="sendcmpct";
const char *CMPCTBLOCK="cmpctblock";
const char *GETBLOCKTXN="getblocktxn";
const char *BLOCKTXN="blocktxn";
}

SendMessages (main.cpp)

SendMessages创建消息并在peer的vSendMsg队列(双端队列或C ++中的“deque”)中对其进行排队。vSendMsg对象基本上只是序列化的数据。

Locks

P2P层主要的锁有:

  • cs_vNodes: 控制对CNode对象的访问
  • cs_vSend: 控制对节点的发送缓存的访问
  • cs_vRecvMsg: 控制对节点的接收缓存的访问
  • cs_inventory

拒绝服务的防范措施

一旦发现异常行为的节点,则直接ban掉。

DoS预防框架在2011年引入。

具体见:https://github.com/bitcoin/bitcoin/pull/517

** 被禁节点 **

被禁节点存储在setBanned中。setBanned是map类型的数据结构,定义为typedef std::map<CSubNet, CBanEntry> banmap_t

默认情况下,一个节点被禁止24小时,但可以使用-bantime选项进行配置。

posted @ 2018-05-28 09:02 lotushy 阅读(1278) 评论(0) 推荐(0) 编辑
摘要: 原文参见:http://www.lotushy.com/?p=113 [TOC] 什么是P2P P2P全称是Peer to peer。P2P计算或P2P网络是一种分布式应用架构。它将任务或负载分发给Peers。在应用中,Peers是平等的、对等的参与者。 从资源角度来讲,Peers将它们拥有的资源如 阅读全文
posted @ 2018-05-24 22:51 lotushy 阅读(1179) 评论(0) 推荐(0) 编辑
摘要: 机器学习是交叉学科,跨计算机科学和统计学领域。与之类似的研究领域,人或动物的神经科学领域。 数据挖掘、人工智能和机器学习三个学科是交叉的,有重叠的。 阅读全文
posted @ 2018-02-07 12:34 lotushy 阅读(473) 评论(0) 推荐(0) 编辑
摘要: Solr 4及之前的版本默认采用VSM(向量空间模型)进行相似度的计算(或打分)。之后的版本,则采用Okapi BM25(一种二元独立模型的扩展),属于概率模型。 阅读全文
posted @ 2018-02-02 17:22 lotushy 阅读(656) 评论(0) 推荐(0) 编辑
摘要: 为什么选择结巴分词 分词效率高 词料库构建时使用的是jieba (python) 结巴分词Java版本 下载 编译 注意 solr tokenizer版本 https://github.com/sing1ee/analyzer solr ( solr 5 ) https://github.com/s 阅读全文
posted @ 2018-02-02 12:40 lotushy 阅读(2214) 评论(3) 推荐(0) 编辑
摘要: @原文地址请关注私人博客: http://www.lotushy.com/?p=100 先谈方法 切书 打印机托盘入纸自动扫描成pdf 导出图片 ocr识别文字 校对 再谈下成本 打印社扫描的成本是一面5毛 我扫的书比较多,不舍得花钱,让小助手用公司打印机扫描的 人力成本一天大概2小时(不经常卡纸的 阅读全文
posted @ 2018-01-24 15:20 lotushy 阅读(731) 评论(0) 推荐(0) 编辑
摘要: 计算方法: n的阶乘记为f(n), s为输入序列, sub(i)为s的i到n的子序列。A(i)为第i位对应的字母在子序列sub(i)中的字典顺序 N(s) = sum_{1,n} T(i) (A(i) 1) + 1 T(i)为i 1的阶乘。 阅读全文
posted @ 2015-10-09 14:00 lotushy 阅读(841) 评论(0) 推荐(0) 编辑
摘要: ```lua --[[ 组合概率 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Description: 某生产零件的工厂为方便管理场内生产的零件种类,现将他们生产的零件从低等到高等零件排序,序号分别为1,2..n,已知该厂的任意几个低等的零件可以组合成更高等的零件,... 阅读全文
posted @ 2015-10-09 13:55 lotushy 阅读(1070) 评论(0) 推荐(0) 编辑
摘要: TOC 数据集 上下文 上下文指用户当前访问所处的环境,如时间,地点,网络类型,机器型号等信息。 隐式反馈数据集 通常是指服务器日志,可能含有上下文,如浏览历史。 显式反馈数据集 通常是指用户调查,反馈模块等的数据,如电影的评分,是否喜欢。 协同过滤 根据用户已有的行为或意见预测当... 阅读全文
posted @ 2015-10-09 13:52 lotushy 阅读(546) 评论(0) 推荐(0) 编辑
摘要: 服务端关注的是高并发,高可靠,易运维,一致性。通俗来讲就是少花钱,多办事,少犯错,易养活。从工业生产角度来看,流水线是比较符合要求的。流水线将复杂的生产流程拆成简单的子流程,将这些子流程串行化,虽没有改变单个产品的生产时间,但提高了并发度。在流水线饱和态下,子流程实际是并行化的,所以并发度提高,进而,大大提升生产效率。同时,由于工人的劳动简化并重复化,工人的效率也得到大副提升。另外,对于维护而言,... 阅读全文
posted @ 2014-10-17 23:24 lotushy 阅读(279) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示