/// <summary> /// 处理 Tracker 请求的方法。 /// </summary> /// <param name="processor">为此请求生成的 <see cref="Kei.KTracker.HttpProcessor"/> 对象。</param> /// <param name="ioStream"><see cref="Kei.KTracker.HttpProcessor"/> 为此请求开启的 <see cref="System.IO.Stream"/>。</param> /// <param name="parameters">URL 请求参数。</param> private void HandleTrackerRequest(HttpProcessor processor, Stream ioStream, string parameters) { // parameters 传入类似 info_hash=XXXX&port=XXXX&ipv6=XXXX 的形式 var args = Utilities.DecomposeParameterString(parameters); Logger.Log("[Tracker]请求: " + processor.RequestUrl); try { Logger.Log("[Tracker]解码收到的参数。"); // 先解码处理各种参数(注意可能会引发异常) string infoHashString = Utilities.UnescapePartialUriEncodedString(args["info_hash"]); InfoHash infoHash = InfoHash.FromHexString(infoHashString); int portNo = Convert.ToInt32(args["port"]); TaskStatus taskStatus; if (args.ContainsKey("event")) { switch (args["event"]) { case "started": taskStatus = TaskStatus.Started; break; case "stopped": taskStatus = TaskStatus.Stopped; break; case "paused": taskStatus = TaskStatus.Paused; break; default: taskStatus = TaskStatus.None; break; } } else { taskStatus = TaskStatus.None; } bool compact; if (args.ContainsKey("compact")) { var n = Convert.ToInt32(args["compact"]); compact = n != 0; } else { compact = false; } bool noPeerID; if (args.ContainsKey("no_peer_id")) { var n = Convert.ToInt32(args["no_peer_id"]); noPeerID = n != 0; } else { noPeerID = false; } var peerIDString = Utilities.UnescapePartialUriEncodedString(args["peer_id"]); // 别忘了重新确认自己 IPEndPoint newMyself = new IPEndPoint(LocalEndPoint.Address, portNo); Logger.Log("[Tracker]新的自己(BitTorrent 客户端): " + newMyself.ToString()); SetMyself(newMyself, peerIDString); List <Peer> peers = null; TrackerCommEventArgs eventArgs; // 如果接入分布网络完成 if (FreeToGo) { // 触发事件,得到新的可用用户列表 if (Seeds.TryGetValue(infoHash, out peers)) { peers = Seeds[infoHash]; if (peers.IndexOf(_myself) < 0) { // 如果之前我不在种子列表中 // TODO: 添加 myself peers.Add(_myself); // 而且此时确认为自己加入网络,强制设定 event=started taskStatus = TaskStatus.Started; } } else { // 如果之前没有相关种子 peers = new List <Peer>(); // TODO: 添加 myself peers.Add(_myself); Seeds.Add(infoHash, peers); // 而且此时确认为自己加入网络,强制设定 event=started taskStatus = TaskStatus.Started; } } eventArgs = new TrackerCommEventArgs(infoHash, peers, portNo, peerIDString, compact, noPeerID, taskStatus); EventHelper.RaiseEventAsync(TrackerComm, this, eventArgs); //if (eventArgs.Peers == null) //{ // throw new NullReferenceException("Peers list is null"); //} if (eventArgs.Peers != null) { peers = eventArgs.Peers; } // 生成返回给 μTorrent 的信息 Logger.Log("[Tracker]反馈给 BitTorrent 客户端。"); if (peers != null) { string peersListString = "[Tracker]种子 " + infoHash.ToString() + " 的用户列表如下:"; foreach (var p in peers) { peersListString += Environment.NewLine + p.EndPoint.ToString(); } Logger.Log(peersListString); } else { Logger.Log("[Tracker]种子 " + infoHash.ToString() + " 的用户列表为空。"); } BEncodedDictionary data = new BEncodedDictionary(); data.Add("interval", 60); if (peers != null) { // 如果种子列表里有种子 // 为了防止其他线程修改这个 list 导致迭代器失效,先锁定这个对象 lock (peers) { if (compact) { // 生成字节数组 byte[] peersArray = new byte[peers.Count * 6]; byte[] tmp; int i = 0; foreach (var peer in peers) { tmp = peer.ToByteArray(); Array.Copy(tmp, 0, peersArray, i * 6, 6); i++; } data.Add("peers", peersArray); } else { // 生成列表 BEncodedList peersList = new BEncodedList(peers.Count); foreach (var peer in peers) { BEncodedDictionary peerDict = new BEncodedDictionary(); peerDict.Add("id", peer.ID); peerDict.Add("ip", peer.EndPoint.GetAddressString()); peerDict.Add("port", peer.EndPoint.GetPortNumber()); peersList.Add(peerDict); } data.Add("peers", peersList); } } data.Add("complete", peers.Count); } else { // 如果没有种子,就返回空列表 data.Add("peers", string.Empty); } // 输出 Logger.Log("[Tracker]写入“成功”头。"); processor.WriteSuccess(null, "text/plain"); Logger.Log("[Tracker]编码返回数据。"); var dataBytes = data.Encode(); Logger.Log("[Tracker]写入返回数据。"); ioStream.Write(dataBytes, 0, dataBytes.Length); Logger.Log("[Tracker]向 BitTorrent 客户端返回了: " + Encoding.ASCII.GetString(dataBytes)); ioStream.Flush(); } catch (Exception ex) { Logger.Log(ex.Message + Environment.NewLine + ex.StackTrace); processor.WriteFailure(); ioStream.WriteLine(ex.Message); ioStream.WriteLine(ex.StackTrace); } }