Ejemplo n.º 1
0
        /// <summary>
        /// 处理 GotPeer 消息。
        /// </summary>
        /// <param name="args">处理时所需要的信息。</param>
        private void HandleGotPeer(HandleMessageArgs args)
        {
            Logger.Log("收到消息: 在其他客户端上找到种子。");
            ushort   bitTorrentClientPort;
            InfoHash infoHash;

            Logger.Log("解码用户及 infohash 数据。");
            MessageFactory.GetPeerMessageContent(args.Message, out infoHash, out bitTorrentClientPort);
            Logger.Log("Infohash: " + infoHash.ToHexString() + Environment.NewLine + "用户端口: " + bitTorrentClientPort.ToString());
            List <Peer> peerList;

            if (!TrackerServer.Seeds.TryGetValue(infoHash, out peerList))
            {
                // 这是本客户端发出的信息,那么本客户端就要接收并处理
                peerList = new List <Peer>(8);
                lock (TrackerServer.Seeds)
                {
                    TrackerServer.Seeds.Add(infoHash, peerList);
                }
            }
            {
                Logger.Log("处理GOTPEER。添加对方地址。");
                KEndPoint ep = args.Message.Header.SourceEndPoint;
                ep.SetPort(bitTorrentClientPort);
                Peer peer = Peer.Create(ep);
                if (!peerList.Contains(peer))
                {
                    lock (peerList)
                    {
                        peerList.Add(peer);
                    }
                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// 处理 PeerExitNetwork 消息。
        /// </summary>
        /// <param name="args">处理时所需要的信息。</param>
        private void HandlePeerExitNetwork(HandleMessageArgs args)
        {
            Logger.Log("收到消息: 用户退出。");
            ushort   bitTorrentClientPort;
            InfoHash infoHash;

            Logger.Log("解码用户及 infohash 数据。");
            MessageFactory.GetPeerMessageContent(args.Message, out infoHash, out bitTorrentClientPort);
            Logger.Log("Infohash: " + infoHash.ToHexString() + Environment.NewLine + "用户端口: " + bitTorrentClientPort.ToString());
            List <Peer> peerList;

            if (TrackerServer.Seeds.TryGetValue(infoHash, out peerList))
            {
                Logger.Log("在本机发现该种子。移出列表。");
                KEndPoint ep = args.Message.Header.SourceEndPoint;
                ep.SetPort(bitTorrentClientPort);
                Peer peer = Peer.Create(ep);
                lock (peerList)
                {
                    peerList.Remove(peer);
                    EventHelper.RaiseEvent(ConnectionListChanged, this, EventArgs.Empty);
                }
            }

            Logger.Log("转发消息。");
            // 转发
            BroadcastMessage(args.Message);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// 处理 ClientExitNetwork 消息。
        /// </summary>
        /// <param name="args">处理时所需要的信息。</param>
        private void HandleClientExitNetwork(HandleMessageArgs args)
        {
            Logger.Log("收到消息: 客户端离开分布网络。");
            KEndPoint remoteEndPoint = args.Message.Header.SourceEndPoint;
            // 只是简单的移除
            int clItemIndex;
            ConnectionListItem item = ConnectionList.FindConnectionListItem(remoteEndPoint, out clItemIndex);

            if (item != null)
            {
                Logger.Log("找到项目并移除。");
                lock (ConnectionList)
                {
                    // 一样,应该不用担心前面的项被移动到后面去导致索引错误的事情吧
                    ConnectionList.RemoveAt(clItemIndex);
                    EventHelper.RaiseEvent(ConnectionListChanged, this, EventArgs.Empty);
                }
            }

            Logger.Log("转发消息。");
            // 转发
            BroadcastMessage(args.Message);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// 处理 PeerEnterNetwork 消息。
        /// </summary>
        /// <param name="args">处理时所需要的信息。</param>
        private void HandlePeerEnterNetwork(HandleMessageArgs args)
        {
            Logger.Log("收到消息: 用户加入。");
            ushort   bitTorrentClientPort;
            InfoHash infoHash;

            Logger.Log("解码用户及 infohash 数据。");
            MessageFactory.GetPeerMessageContent(args.Message, out infoHash, out bitTorrentClientPort);
            Logger.Log("Infohash: " + infoHash.ToHexString() + Environment.NewLine + "用户端口: " + bitTorrentClientPort.ToString());
            List <Peer> peerList;

            if (TrackerServer.Seeds.TryGetValue(infoHash, out peerList))
            {
                Logger.Log("在本机发现该种子。加入列表。");
                KEndPoint remoteClientEP = args.Message.Header.SourceEndPoint;
                KEndPoint remoteBTEP     = remoteClientEP;
                remoteBTEP.SetPort(bitTorrentClientPort);
                Peer peer = Peer.Create(remoteBTEP);
                if (!peerList.Contains(peer))
                {
                    lock (peerList)
                    {
                        peerList.Add(peer);
                    }
                }

                // 同时报告信息源,我这里有种子
                Logger.Log("报告消息源在这里找到种子。");
                // 此时 ep 的 Port 已经被修改,所以不能直接向 ep 所表示的端点发送,之前写错了……
                // 所以后面索性改了名称,remoteClientEP 和 remoteBTEP
                SendMessage(remoteClientEP, MessageFactory.GotPeer(LocalKEndPoint, infoHash, (ushort)TrackerServer.Myself.EndPoint.GetPortNumber()));
            }

            Logger.Log("转发消息。");
            // 转发
            BroadcastMessage(args.Message);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// 消息处理的核心分发过程。
        /// </summary>
        /// <param name="args">处理时需要的信息。</param>
        private void HandleMessage(HandleMessageArgs args)
        {
            Logger.Log("KClient::HandleMessage() from " + args.Message.Header.SourceEndPoint.ToString() + " with code " + args.Message.Header.Code.ToString());
            // 确保不是自己发出的消息
            if (!args.Message.Header.SourceEndPoint.Equals(_localKEndPoint))
            {
                KHandledMessage handledMessage;
                int             handledMessageIndex;
                handledMessage = HandledMessages.FindHandledMessage(args.Message, out handledMessageIndex);
                string tmpLog;
                tmpLog  = "消息代码: " + args.Message.Header.Code.ToString();
                tmpLog += Environment.NewLine + "消息唯一编码: " + args.Message.Header.MessageID.ToString();
                tmpLog += Environment.NewLine + "消息来源: " + args.Message.Header.SourceEndPoint.ToString();
                Logger.Log(tmpLog);
                // 若未处理过该消息
                if (handledMessage == null)
                {
                    Logger.Log("未处理过该消息。");
                    switch (args.Message.Header.Code)
                    {
                    case KMessageCode.ReportAlive:
                        if (!args.Message.Header.SourceEndPoint.AddressEquals(IPAddress.Loopback))
                        {
                            HandleReportAlive(args);
                            AddToConnectionList(args.Message.Header.SourceEndPoint);
                        }
                        break;

                    case KMessageCode.ClientEnterNetwork:
                        HandleClientEnterNetwork(args);
                        if (args.RealPort == 0)
                        {
                            // 这条消息是用来连接到接入点的,此时对方还未初始化完毕,所以不用判断源端点的事情
                            AddToConnectionList(KEndPoint.FromEndPoint(args.EndPoint));
                        }
                        else
                        {
                            // 这是接入点连接到接入点的请求
                            // 此时地址是真实的,监听端口由 args.RealPort 反映
                            var kep = KEndPoint.FromEndPoint(args.EndPoint);
                            kep.SetPort(args.RealPort);
                            AddToConnectionList(kep);
                        }
                        break;

                    case KMessageCode.ClientExitNetwork:
                        if (!args.Message.Header.SourceEndPoint.AddressEquals(IPAddress.Loopback))
                        {
                            HandleClientExitNetwork(args);
                            // 既然退出了为什么还要保留这个项
                            //AddToConnectionList(args.Message.Header.SourceEndPoint);
                        }
                        break;

                    case KMessageCode.PeerEnterNetwork:
                        if (!args.Message.Header.SourceEndPoint.AddressEquals(IPAddress.Loopback))
                        {
                            HandlePeerEnterNetwork(args);
                            AddToConnectionList(args.Message.Header.SourceEndPoint);
                        }
                        break;

                    case KMessageCode.PeerExitNetwork:
                        if (!args.Message.Header.SourceEndPoint.AddressEquals(IPAddress.Loopback))
                        {
                            HandlePeerExitNetwork(args);
                            AddToConnectionList(args.Message.Header.SourceEndPoint);
                        }
                        break;

                    case KMessageCode.GotPeer:
                        if (!args.Message.Header.SourceEndPoint.AddressEquals(IPAddress.Loopback))
                        {
                            HandleGotPeer(args);
                            AddToConnectionList(args.Message.Header.SourceEndPoint);
                        }
                        break;

                    default:
                        return;
                    }

                    Logger.Log("将消息加入“已处理”列表。");
                    // 对于收到的信息,都加入“已处理消息”列表
                    lock (HandledMessages)
                    {
                        HandledMessages.Add(new KHandledMessage(args.Message));
                    }
                }
                else
                {
                    Logger.Log("更新消息生命周期。");
                    // 更新生命周期,并将其移动到列表最后(因为是“刚刚加入”的)
                    handledMessage.LifeStart = DateTime.Now;
                    lock (HandledMessages)
                    {
                        // 访问这个过程的只有一个线程,所以不用担心说前面某一项先被移动到后面去了导致索引错误
                        HandledMessages.RemoveAt(handledMessageIndex);
                        HandledMessages.Add(handledMessage);
                    }
                    Logger.Log("清理“已处理”列表。");
                    SweepHandledMessages();
                }
            }
        }
Ejemplo n.º 6
0
        /// <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);
        }
Ejemplo n.º 7
0
 /// <summary>
 /// 处理 ReportAlive 消息。
 /// </summary>
 /// <param name="args">处理时所需要的信息。</param>
 private void HandleReportAlive(HandleMessageArgs args)
 {
     // 这是一个报告存活的消息
     Logger.Log("收到消息: 报告存活。");
     // 不采取任何行动;后面会自动将对方加入连接列表
 }