🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# Go网络与协议 ![](https://img.kancloud.cn/a1/34/a13423b8125805ebfcf1e6f496cbaa2b_340x286.png) **TCP/IP 协议族:** * ARP: Address Resolution Protocol, 正向地址解析协议。通过已知的IP,寻找对应的主机MAC地址。 * RARP:是反响的地址转换协议,通过MAC地址确定IP地址。 * IP:Internet Protocol,是因特网互联协议 * ICMP:Internet Control Message Protocol,是Internet控制报文协议,它是TCP/IP协议的一个子协议,用于在IP主机、路由器之间传递控制消息。 eg: ping 127.0.0.1 就是用到了ICMP协议 * IGMP:Internet Group Management Protocol,是Internet组管理协议,它是因特网协议家族中的一个`组播`协议,该协议运行在主机和组播路由器之间。 * TCP:Transmission Control Protocol,传输控制协议,是一种面向连接的、可靠的、基于字节流的传输层通信协议。主要用于 文件传输 * UDP:User Datagram Protocol,是OSI参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。主要用于 聊天 * FTP * Telnet * TFTP * NFS ![](https://img.kancloud.cn/b6/34/b634e73d270b8e8b653b4485fe89e0b4_362x219.png) **通信的拆包与组包:** ![](https://img.kancloud.cn/23/2b/232b5055d020de81ce9949c1ffd32315_1044x398.png) # Socket编程 TCP的 C/S架构: **cs模型:客户端和服务器** 客户端 ===》 客户 1)主动请求服务 服务器 ===》 客服 1)被动提供服务 ![](https://img.kancloud.cn/35/54/3554633dd947b94ef5f868d741ca36e6_438x477.png) # Go网络通信编程 ## 服务器端 ![](https://img.kancloud.cn/5b/cd/5bcd8b5ebeaa6ebf7f97919468a1988c_1570x1019.png) 在区块链中,每一个节点既是服务器,也是客户端。 首先服务器在当前节点开启监听,protocol为tcp。在函数startserver退出后,关闭l服务器监听器ln句柄。 同时作为客户端,给中心节点发送version命令,请求区块版本(高度)检查和同步。 接下来进入无限循环,服务器监听器阻塞,等待客户端连接,并通过并发模式,接收来自客户端的连接请求,该并发任务协程会被放到服务器堆栈。该协程的名称是handleConnection。 ## 客户端 ![](https://img.kancloud.cn/e5/9e/e59eb764d4c5594093f48801b3fceea1_1369x874.png) 客户端通过方法net.Dial连接到服务器。在本函数执行完毕,将关闭与服务器的连接。 接下来将消息写入到conn通道。 ## 服务器端 ![](https://img.kancloud.cn/5b/86/5b86055a902112974a2f0621d9a17d95_850x1089.png) 服务器端接收到客户端的连接,阻塞解除,协程handleConnection被调用执行。 在handleConnection中,首先通过ioutil读取conn上的所有数据,然后解析命令。注意命令为12个字节(commandLength),request则是command+payload构成,payload在各个具体命令的handle中进行解析。 接下来,根据command,转到相应的处理函数中进行处理。 ![](https://img.kancloud.cn/05/bf/05bfbe6cb721a1bae9d147a82b8ea649_1180x588.png) 最后关闭通信连接。 # 区块链的服务器和客户端 1、区块链是P2P网络,因此加入区块链的每一个节点,既是服务器,也是客户端。 所以,一般在sendData时候,都会将发送者的addr作为payload的一部分,发送给对方。 2、P2P通信,是点对点的强通信方式,多次请求-回答完成交互,从发送“麻烦告诉我你版本是什么”开始,发现本地版本比对方低,于是接着发送“麻烦告诉我你有什么”,对方将回复区块或交易的概要(哈希列表),再紧接着向对方要具体的数据(如某个区块或者某个交易)。 3、由于是P2P通信,所以每次请求-回答的数据都很小:在区块链中,每次请求只会请求一个区块的数据或者一个交易的数据,这将最大限度保证通信的可靠性。 # Multiaddress 多地址(通常缩写为multiaddr)是一种约定,用于将多层寻址信息编码为单个“面向未来”的路径结构。 例如:/ip4/127.0.0.1/udp/1234对两个协议及其基本寻址信息进行编码。 /ip4/127.0.0.1通知我们,我们需要IPv4协议的127.0.0.1回送地址,而/ udp / 1234告诉我们,我们希望将UDP数据包发送到端口1234。 可以组成多地址来描述地址的多个“层”。 例如,multiaddr`/p2p/QmYyQSo1c1Ym7orWxLYvCrM2EmxFTANf8wXmmE7DWjhx5N`唯一标识我的本地 IPFS 节点, 使用 libp2p的[注册的协议ID](https://github.com/multiformats/multiaddr/blob/master/protocols.csv)`/p2p/`和我的IPFS节点公钥的[multihash](https://docs.libp2p.io/reference/glossary/#multihash)。 ## Multiaddr简介: Multiaddr aims to make network addresses future-proof, composable, and efficient. Current addressing schemes have a number of problems. 1. They hinder protocol migrations and interoperability between protocols. 2. They don't compose well. There are plenty of X-over-Y constructions, but only few of them can be addressed in a classic URI/URL or host:port scheme. 3. They don't multiplex: they address ports, not processes. 4. They're implicit, in that they presume out-of-band values and context. 5. They don't have efficient machine-readable representations. Multiaddr solves these problems by modelling network addresses as arbitrary encapsulations of protocols. * Multiaddrs support addresses for any network protocol. * Multiaddrs are self-describing. * Multiaddrs conform to a simple syntax, making them trivial to parse and construct. * Multiaddrs have human-readable and efficient machine-readable representations. * Multiaddrs encapsulate well, allowing trivial wrapping and unwrapping of encapsulation layers. Multiaddr was originally[thought up by @jbenet](https://github.com/jbenet/random-ideas/issues/11). 翻译如下: Multiaddr的目标是使网络地址可适应未来需求,可组合且高效。 当前的寻址方案具有许多问题。 1. 它们阻碍协议迁移和协议之间的互操作性。 2. 他们表现不佳。有很多X-over-Y构造,但是只有少数可以用经典的URI / URL或host:port方案进行寻址。 3. 它们不复用:它们寻址端口,而不是进程。 4. 它们是隐式的,因为它们假定带外值和上下文。 5. 它们没有有效的机器可读表示。 Multiaddr通过将网络地址建模为协议的任意封装来解决这些问题。 1. Multiaddr支持任何网络协议的地址。 2. Multiaddr是自我描述的。 3. Multiaddr遵循简单的语法,使其易于解析和构造。 4. Multiaddr具有人类可读和有效的机器可读表示形式。 5. Multiaddr可以很好地封装,从而可以轻松封装和解开封装层。 Multiaddr最初是由[@jbenet](https://github.com/jbenet/random-ideas/issues/11)想到的。 # 以太坊的KAD协议 以太坊Kad网络中节点间通信基于UDP,主要由以下几个命令构成,若两个节点间PING-PONG握手通过,则认为相应节点在线。 ![](https://img.kancloud.cn/13/56/135653d8a2b611e50ccb5db93f3a76df_1374x1373.png) # 以太坊的邻居节点 C++版本以太坊源码中,NodeTable是以太坊 P2P网络的关键类,所有与邻居节点相关的数据和方法均由NodeTable类实现。 ![](https://img.kancloud.cn/97/e9/97e96fe3009635ceeab7a7ab1221e6d3_877x492.png) ![](https://img.kancloud.cn/58/81/5881c8451fd0846d3df795f7a488f93b_846x1295.png) ![](https://img.kancloud.cn/e4/25/e4252f9adeffcd2307d55afbf32b7e62_851x759.png) ## 邻居节点发现方法  邻居节点是指加入到K桶,并通过PING-PONG握手的节点。 ![](https://img.kancloud.cn/b8/8b/b88bcdcfbafec5c738f968c411d9c4ec_629x651.png) 邻居节点发现流程说明: 1. 系统第一次启动随机生成本机节点NodeId,记为LocalId,生成后将固定不变,本地节点记为local-eth。 2. 系统读取公共节点信息,ping-pong握手完成后,将其写入K桶。 3. 系统每隔7200ms刷新一次K桶。 4. 刷新K桶流程如下: a.      随机生成目标节点Id,记为TargetId,从1开始记录发现次数和刷新时间 b.      计算TargetId与LocalId的距离,记为Dlt c.      K桶中节点的NodeId记为KadId,计算KadId与TargetId的距离,记为Dkt d.      找出K桶中Dlt大于Dkt的节点,记为k桶节点,向k桶节点发送FindNODE命令,FindNODE命令包含TargetId e.      K桶节点收到FindNODE命令后,同样执行b-d的过程,将从K桶中找到的节点使用Neighbours命令发回给本机节点。 f.       本机节点收到Neighbours后,将收到的节点写入到K桶中。 g.      若搜索次数不超过8次,刷新时间不超过600ms,则返回到b步骤循环执行。 ## 邻居节点网络拓扑及刷新机制 ![](https://img.kancloud.cn/0c/ba/0cbaaee11b8bc1264b6c62f1309627ef_640x735.png) 1 TargetId为随机生成的虚拟节点ID。 2 以太坊Kad网络与传统Kad网络的区别: 1. 以太坊节点在发现邻居节点的8次循环中,所查找的节点均在距离上向随机生成的TargetId收敛。 2. 传统Kad网络发现节点时,在距离上向节点本身收敛。