网络管理
节点管理
public class Node : IDisposable
{
private readonly IListener listener;
private readonly NodeOptions options;
private readonly IPeerFactory peerFactory;
public Node(IWallet miner, IListener listener, IPeerFactory peerFactory, NodeOptions options = null)
{
this.Engine = new Engine(miner);
this.options = options ?? new NodeOptions();
this.listener = listener;
this.listener.Start();
this.peerFactory = peerFactory;
this.ConnPool = new ConnectionPool(this, this.options.WellKnownNodes, this.peerFactory, this.listener);
this.ConnPool.Start();
}
public Engine Engine { get; }
public ConnectionPool ConnPool { get; }
public void Dispose()
{
this.Engine?.Dispose();
this.listener.Dispose();
this.ConnPool.Dispose();
this.peerFactory.Dispose();
}
}
public class NodeOptions
{
public string[] WellKnownNodes { get; set; }
}
连接管理
public enum ConnectionStatus
{
Initial,
Connected,
Disconnected,
Dead,
}
public class ConnectionNode
{
public string Address { get; set; }
public ConnectionStatus Status { get; set; }
public IPeer Peer { get; set; }
}
public class ConnectionPool : IDisposable
{
private readonly List<ConnectionNode> nodes;
private readonly Node selfNode;
private readonly IPeerFactory peerFactory;
private readonly IListener listener;
public ConnectionPool(Node node, string[] wellKnowns, IPeerFactory peerFactory, IListener listener)
{
this.selfNode = node;
this.nodes = wellKnowns
.Where(_ => _ != listener.Address)
.Select(_ => new ConnectionNode(_))
.ToList();
this.peerFactory = peerFactory;
this.listener = listener;
}
public void Start()
public void Dispose()
}
public class ConnectionPool : IDisposable
{
private bool isReceiving = false;
private Thread thReceive;
public event EventHandler<CommandBase> OnCommandReceived;
public void Start()
{
this.thReceive = new Thread(Receive);
this.thReceive.Start();
this.isReceiving = true;
}
private void Receive()
{
while (this.isReceiving)
{
ConnectionNode[] internalnodes;
lock (this.nodes)
{
internalnodes = this.nodes.ToArray();
}
foreach (var node in internalnodes)
{
if (node.Peer == null) continue;
var command = node.Peer.Receive();
if (command == null) continue;
OnCommandReceived?.Invoke(this, command);
command.OnReceived(this.selfNode, node);
if (!this.isReceiving) break;
}
Thread.Sleep(500);
}
}
}
节点连接
public class ConnectionPool : IDisposable
{
private Timer reconnectTimer;
public void Start()
{
...
this.reconnectTimer = new Timer((_) => this.ConnectAll(), null, new TimeSpan(0, 0, 0, 0, 100), new TimeSpan(0, 0, 20));
}
private void ConnectAll()
{
ConnectionNode[] internalnodes;
lock (this.nodes)
{
internalnodes = this.nodes
.Where(_ => _.Status == ConnectionStatus.Initial || _.Status == ConnectionStatus.Dead)
.Where(_ => _.Address != null)
.ToArray();
}
foreach (var node in internalnodes)
{
this.TryConnect(node);
}
}
}
public class ConnectionPool : IDisposable
{
private Timer reconnectTimer;
public void Start()
{
...
this.reconnectTimer = new Timer((_) => this.ConnectAll(), null, new TimeSpan(0, 0, 0, 0, 100), new TimeSpan(0, 0, 20));
}
private void ConnectAll()
{
ConnectionNode[] internalnodes;
lock (this.nodes)
{
internalnodes = this.nodes
.Where(_ => _.Status == ConnectionStatus.Initial || _.Status == ConnectionStatus.Dead)
.Where(_ => _.Address != null)
.ToArray();
}
foreach (var node in internalnodes)
{
this.TryConnect(node);
}
}
}
private void TryConnect(ConnectionNode node)
{
if (node.Peer != null)
{
node.Peer.Dispose();
node.Peer = null;
}
var peer = this.peerFactory.Produce();
try
{
peer.Connect(node.Address);
node.Peer = peer;
}
catch (Exception)
{
node.Status = ConnectionStatus.Dead;
}
if (!peer.IsConnected)
{
Debug.WriteLine("open peer channel failed");
node.Status = ConnectionStatus.Dead;
return;
}
try
{
peer.Send(new VersionCommand());
}
catch (Exception)
{
node.Status = ConnectionStatus.Dead;
}
finally
{
if (node.Status != ConnectionStatus.Connected)
{
peer.Close();
peer.Dispose();
}
}
}
public class VersionCommand : CommandBase
{
public override void OnReceived(Node node, ConnectionNode connectionNode)
{
connectionNode.Status = ConnectionStatus.Connected;
connectionNode.Peer.Send(new VersionAcknowledgeCommand());
}
}
public class VersionAcknowledgeCommand : CommandBase
{
public override void OnReceived(Node node, ConnectionNode connectionNode)
{
connectionNode.Status = ConnectionStatus.Connected;
}
}