/* * Check to see if any of this node's neighbors * should be neighbors of us. If they should, connect * to the closest such nodes on each side. * * @param structs a ConnectionList of ConnectionType.Structured * @param neighbors an IEnumerable of NodeInfo objects * @param nltarget an address of a node that should be on our left * @param nrtarget an address of a node that should be on our right */ protected void CheckForNearerNeighbors(ConnectionList structs, IEnumerable neighbors, out Address nltarget, out Address nrtarget) { BigInteger ldist = null; BigInteger rdist = null; nltarget = null; nrtarget = null; AHAddress local = (AHAddress)_node.Address; foreach (NodeInfo ni in neighbors) { if (!(_node.Address.Equals(ni.Address) || structs.Contains(ni.Address))) { AHAddress adr = (AHAddress)ni.Address; int n_left = structs.LeftInclusiveCount(_node.Address, adr); int n_right = structs.RightInclusiveCount(_node.Address, adr); if (n_left < DESIRED_NEIGHBORS || n_right < DESIRED_NEIGHBORS) { //We should connect to this node! if we are not already: BigInteger adr_dist = local.LeftDistanceTo(adr); if ((null == ldist) || adr_dist < ldist) { ldist = adr_dist; nltarget = adr; } adr_dist = local.RightDistanceTo(adr); if ((null == rdist) || adr_dist < rdist) { rdist = adr_dist; nrtarget = adr; } } } } }
/* * Check to see if any of this node's neighbors * should be neighbors of us. If they should, connect * to the closest such nodes on each side. * * @param structs a ConnectionList of ConnectionType.Structured * @param neighbors an IEnumerable of NodeInfo objects * @param nltarget an address of a node that should be on our left * @param nrtarget an address of a node that should be on our right */ protected void CheckForNearerNeighbors(ConnectionList structs, IEnumerable neighbors, out Address nltarget, out Address nrtarget) { BigInteger ldist = null; BigInteger rdist = null; nltarget = null; nrtarget = null; AHAddress local = (AHAddress)_node.Address; foreach(NodeInfo ni in neighbors) { if( !( _node.Address.Equals(ni.Address) || structs.Contains(ni.Address) ) ) { AHAddress adr = (AHAddress)ni.Address; int n_left = structs.LeftInclusiveCount(_node.Address, adr); int n_right = structs.RightInclusiveCount(_node.Address, adr); if( n_left < DESIRED_NEIGHBORS || n_right < DESIRED_NEIGHBORS ) { //We should connect to this node! if we are not already: BigInteger adr_dist = local.LeftDistanceTo(adr); if( ( null == ldist ) || adr_dist < ldist ) { ldist = adr_dist; nltarget = adr; } adr_dist = local.RightDistanceTo(adr); if( ( null == rdist ) || adr_dist < rdist ) { rdist = adr_dist; nrtarget = adr; } } } } }
///</summary>Creates a new Graph for simulate routing algorithms.</summary> ///<param name="count">The network size not including the clusters.</param> ///<param name="near">The amount of connections on the left or right of a ///node.</param> ///<param name="shortcuts">The amount of far connections had per node.</param> ///<param name="latency">(optional)count x count matrix containing the ///latency between ///two points.</param> ///<param name="cluster_count">A cluster is a 100 node network operating on ///a single point in the network. A cluster cannot communicate directly ///with another cluster.</param> ///<param name="dataset">A square dataset consisting of pairwise latencies.</param> public Graph(int count, int near, int shortcuts, int random_seed, List <List <int> > dataset) { _rand = new Random(random_seed); if (dataset != null) { if (count >= dataset.Count) { _latency_map = dataset; } else { // If the count size is less than the data set, we may get inconclusive // results as network size changes due to the table potentially being // heavy set early and lighter later. This randomly orders all entries // so that multiple calls to the graph will provide a good distribution. Dictionary <int, int> chosen = new Dictionary <int, int>(count); for (int i = 0; i < count; i++) { int index = _rand.Next(0, dataset.Count - 1); while (chosen.ContainsKey(index)) { index = _rand.Next(0, dataset.Count - 1); } chosen.Add(i, index); } _latency_map = new List <List <int> >(dataset.Count); for (int i = 0; i < count; i++) { List <int> map = new List <int>(count); for (int j = 0; j < count; j++) { map.Add(dataset[chosen[i]][chosen[j]]); } _latency_map.Add(map); } } } GraphNode.SetSeed(_rand.Next()); _addr_to_node = new Dictionary <AHAddress, GraphNode>(count); _addrs = new List <AHAddress>(count); _addr_to_index = new Dictionary <AHAddress, int>(count); // first we create our regular network while (_addrs.Count < count) { AHAddress addr = GenerateAddress(); _addr_to_node[addr] = CreateNode(addr); _addrs.Add(addr); } FixLists(); for (int i = 0; i < count; i++) { GraphNode cnode = _addr_to_node[_addrs[i]]; ConnectionList cons = cnode.ConnectionTable.GetConnections(ConnectionType.Structured); // We select our left and right neighbors up to near out (so we get 2*near connections) // Then we check to make sure we don't already have this connection, since the other guy // may have added it, if we don't we create one and add it. for (int j = 1; j <= near; j++) { int left = i - j; if (left < 0) { left += count; } GraphNode lnode = _addr_to_node[_addrs[left]]; if (!cons.Contains(lnode.Address)) { int delay = CalculateDelay(cnode, lnode); AddConnection(cnode, lnode, delay); AddConnection(lnode, cnode, delay); } int right = i + j; if (right >= count) { right -= count; } GraphNode rnode = _addr_to_node[_addrs[right]]; // No one has this connection, let's add it to both sides. if (!cons.Contains(rnode.Address)) { int delay = CalculateDelay(cnode, rnode); AddConnection(cnode, rnode, delay); AddConnection(rnode, cnode, delay); } } // Let's add shortcuts so that we have at least the minimum number of shortcuts while (cnode.Shortcuts < shortcuts) { cons = cnode.ConnectionTable.GetConnections(ConnectionType.Structured); AHAddress addr = ComputeShortcutTarget(cnode.Address); addr = FindNodeNearestToAddress(addr); if (cons.Contains(addr) || addr.Equals(cnode.Address)) { continue; } GraphNode snode = _addr_to_node[addr]; cons = snode.ConnectionTable.GetConnections(ConnectionType.Structured); int delay = CalculateDelay(cnode, snode); if (delay == -1) { continue; } AddConnection(cnode, snode, delay); AddConnection(snode, cnode, delay); cnode.Shortcuts++; snode.Shortcuts++; } } foreach (GraphNode gn in _addr_to_node.Values) { gn.UpdateSystem(); } }
///////////////// Methods ////////////////////// /** * Starts the Overlord if we are active * * This method is called by the CheckState method * IF we have not seen any connections in a while * AND we still need some connections * */ public override void Activate() { #if POB_DEBUG Console.Error.WriteLine("In Activate: {0}", _node.Address); #endif if (IsActive == false) { return; } DateTime now = DateTime.UtcNow; lock ( _sync ) { if (now - _last_retry_time < _current_retry_interval) { //Not time yet... return; } _last_retry_time = now; //Double the length of time we wait (resets to default on connections) _current_retry_interval += _current_retry_interval; _current_retry_interval = (_MAX_RETRY_INTERVAL < _current_retry_interval) ? _MAX_RETRY_INTERVAL : _current_retry_interval; } ConnectionTable tab = _node.ConnectionTable; //If we are going to connect to someone, this is how we //know who to use Address target = null; string contype = String.Empty; ISender sender = null; int desired_ctms = 1; ConnectionList structs = tab.GetConnections(ConnectionType.Structured); if (structs.Count < 2) { ConnectionList leafs = tab.GetConnections(ConnectionType.Leaf); if (leafs.Count == 0) { /* * We first need to get a Leaf connection */ return; } //We don't have enough connections to guarantee a connected //graph. Use a leaf connection to get another connection Connection leaf = null; //Make sure the following loop can't go on forever int attempts = 2 * leafs.Count; do { leaf = leafs[_rand.Next(leafs.Count)]; attempts--; }while(leafs.Count > 1 && structs.Contains(leaf.Address) && attempts > 0); //Now we have a random leaf that is not a //structured neighbor to try to get a new neighbor with: if (leaf != null) { target = GetSelfTarget(); /* * This is the case of trying to find the nodes nearest * to ourselves, use the Annealing routing to get connected * more quickly */ sender = new ForwardingSender(_node, leaf.Address, target); //We are trying to connect to the two nearest nodes in one //one attempt, so wait for two distinct responses: desired_ctms = 2; //This is a near neighbor connection contype = STRUC_NEAR; } } if (structs.Count > 0 && sender == null) { /** * We need left or right neighbors we send * a ConnectToMessage in the directons we * need. */ if (NeedLeftNeighbor) { #if POB_DEBUG Console.Error.WriteLine("NeedLeftNeighbor: {0}", _node.Address); #endif target = new DirectionalAddress(DirectionalAddress.Direction.Left); short ttl = (short)DESIRED_NEIGHBORS; sender = new AHSender(_node, target, ttl, AHHeader.Options.Last); contype = STRUC_NEAR; } else if (NeedRightNeighbor) { #if POB_DEBUG Console.Error.WriteLine("NeedRightNeighbor: {0}", _node.Address); #endif target = new DirectionalAddress(DirectionalAddress.Direction.Right); short ttl = (short)DESIRED_NEIGHBORS; sender = new AHSender(_node, target, ttl, AHHeader.Options.Last); contype = STRUC_NEAR; } } if (sender != null) { ConnectTo(sender, target, contype, desired_ctms); } }
/// <summary> /// 处理 ClientEnterNetwork 消息。 /// </summary> /// <param name="args">处理时需要的信息。</param> private void HandleClientEnterNetwork(HandleMessageArgs args) { Logger.Log("收到消息: 客户端加入分布网络。"); KEndPoint remoteEndPoint = args.Message.Header.SourceEndPoint; int isMessageHandled = 0; ushort realPort = 0; if (args.Message.Content.Data.Length > 0) { BEncodedDictionary dict; dict = BEncodedValue.Decode <BEncodedDictionary>(args.Message.Content.Data); isMessageHandled = (int)((dict["message handled"] as BEncodedNumber).Number); realPort = (ushort)((dict["real port"] as BEncodedNumber).Number); } string enterArgsRecord = "ClientEnterNetwork Args:"; enterArgsRecord += Environment.NewLine + "isMessageHandled: " + isMessageHandled.ToString(); enterArgsRecord += Environment.NewLine + "realPort: " + realPort.ToString(); Logger.Log(enterArgsRecord); args.RealPort = realPort; if (!ConnectionList.Contains(remoteEndPoint)) { if (isMessageHandled == 0) { Logger.Log("本客户端是第一个收到这条进入消息的客户端。" + Environment.NewLine + "本机的连接列表如下。"); StringBuilder sb = new StringBuilder(100); lock (ConnectionList) { foreach (var item in ConnectionList) { sb.AppendLine(item.ToString()); } } Logger.Log(sb.ToString()); Logger.Log("将当前连接信息编码并发送。我眼中的对方: " + args.EndPoint.ToString()); // 将自己的连接列表和用户列表编码,准备发送到连接来的客户端 var data = EncodeTargetInformation(args.EndPoint); // 然后要修正 remoteEndPoint,因为加入消息必定是 127.0.0.1:ep 形式,所以要修正为实际的 ep remoteEndPoint = KEndPoint.FromEndPoint(args.EndPoint); try { // 先返回接下来的字节大小 args.Stream.WriteInt32(data.Length); // 然后一次性发送 args.Stream.Write(data, 0, data.Length); args.Stream.Flush(); } catch (Exception ex) { // 首次通信就失败了…… Logger.Log(ex.Message); Logger.Log(ex.StackTrace); } } } KMessage message = args.Message; if (isMessageHandled == 0) { // 注意:虽然 KMessage 是一个值类型,但是其中含有引用类型(数组),这里修改了这个引用类型 Logger.Log("设置该消息为处理过。"); message.Content.Data = BitConverter.GetBytes((int)1); } else { // 本客户端不是第一个处理的,那就报告存活吧 SendMessage(remoteEndPoint, MessageFactory.ReportAlive(LocalKEndPoint)); } Logger.Log("转发消息。"); // 转发 BroadcastMessage(message); }