/*
         * 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;
            }
          }
        }
      }
    }
Example #3
0
        ///</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);
        }