使用 Monotorrent 在 VB.NET 中加载 Torrent

Posted

技术标签:

【中文标题】使用 Monotorrent 在 VB.NET 中加载 Torrent【英文标题】:Load Torrent in VB.NET with Monotorrent 【发布时间】:2016-02-20 20:40:04 【问题描述】:

我正在制作一个简单的应用程序来下载种子文件,使用 MonoTorrent。但我无法正确加载种子,我查看了所有可用信息。

这是我使用的代码:

    Imports MonoTorrent.BEncoding
Imports MonoTorrent.Client
Imports MonoTorrent.Client.Tracker
Imports MonoTorrent.Common
Imports System.IO
Imports System.Net
Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    End Sub
End Class
Module BitTorrentAnnounceReader
    Sub main()

        'load Torrentfile
        Dim TorrentFile As torrent = ("D:\youtorrent.torrent")
        Console.WriteLine(TorrentFile.Name)

        'generate annouce paramters
        'since we simluate a BitTornado Client double check PeerID and Key Paramter
        Dim AnnounceParameter As New AnnounceParameters
        AnnounceParameter.BytesLeft = TorrentFile.Size
        AnnounceParameter.BytesUploaded = 0
        AnnounceParameter.BytesDownloaded = 0
        AnnounceParameter.Port = 12224
        AnnounceParameter.InfoHash = TorrentFile.InfoHash
        AnnounceParameter.PeerId = "T03I-----" & GenerateTorrentClientKeys(11, 1)
        AnnounceParameter.ClientEvent = TorrentEvent.Started

        'a torrentfile can have more than one url, we use only the first one
        'the url should have http to work for this example
        Dim AnnounceUrl As String = TorrentFile.AnnounceUrls.Item(0).Item(0).ToString
        Console.WriteLine(AnnounceUrl)

        'the full announceurl that will fired to tracker
        'we are simulating a BitTorando Client
        Dim FullAnnounceUrl As String = CreateAnnounceString(AnnounceParameter, AnnounceUrl, GenerateTorrentClientKeys(6))

        'building a webrequest for tracker request; some silly line look at comments on
        'MonoTorrent.Client.Tracker.HTTPTracker.Announce
        Dim req As HttpWebRequest = CType(WebRequest.Create(FullAnnounceUrl), HttpWebRequest)
        req.KeepAlive = False
        req.Proxy = New WebProxy

        'we want to simulate a BitTornado Client, so http headers
        req.UserAgent = "User-Agent: BitTornado/T-0.3.18"

        'to simulate full client we need also gzip but for better usage we dont use it
        ' req.Headers.Add("Accept-Encoding", "gzip")
        ' If (resp.ContentEncoding.ToLower().Contains("gzip")) Then
        ' Str = New IO.Compression.GZipStream(Str, IO.Compression.CompressionMode.Decompress)

        Dim response As HttpWebResponse = req.GetResponse
        Dim fs As Stream = WebResponseToStream(response)

        Dim peers As List(Of Peer) = AnnounceGetPeerList(fs)
        Console.WriteLine("Tracker returned:" & peers.Count)
        For Each PeerInfo As Peer In peers
            Console.WriteLine(PeerInfo.ConnectionUri.Host & ":" & PeerInfo.ConnectionUri.Port)
        Next

        Console.ReadKey()
    End Sub
    ''' <summary>
    ''' Generate a random key depending on which TorrentClient to simulate
    ''' </summary>
    ''' <param name="len"></param>
    ''' <param name="keys"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function GenerateTorrentClientKeys(ByVal len As Integer, Optional ByVal keys As Integer = 1) As String

        Dim Chars() As String = "abcdefghijklmnopqrstuvwxyz0123456789", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
        'Chars[0] = uTorrent Keys
        'Chars[1] = BitTornado Keys
        Dim str As String = ""
        Dim r As New System.Random()

        For i = 1 To len
            str &= Chars(keys).Substring(r.Next(1, Chars(keys).Length), 1)
        Next

        Return str

    End Function
    ''' <summary>
    ''' A simple way of parsing a bencoded peerlist. it will autodecode compact mode request
    ''' you can find the full announce parser in the orignal file:
    ''' 
    ''' MonoTorrent.Client.Tracker.HTTPTracker.HandleAnnounce
    ''' http://anonsvn.mono-project.com/viewvc/trunk/bitsharp/src/MonoTorrent/MonoTorrent.Client/Tracker/HTTPTracker.cs
    ''' </summary>
    ''' <param name="fs"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function AnnounceGetPeerList(ByVal fs As Stream) As List(Of Peer)
        'you can also use a file with a torrenrequest
        'Dim reader As New RawReader(IO.File.Open("file.req", IO.FileMode.Open), False)

        'decode the bencoded stream
        Dim dictionary As BEncodedDictionary = BEncodedValue.Decode(Of BEncodedDictionary)(fs)

        Dim peers As New List(Of Peer)
        For Each keypair In dictionary
            Select Case keypair.Key.ToString
                Case "interval"
                    'MsgBox TimeSpan.FromSeconds(int.Parse(keypair.Value.ToString())); 
                    'MsgBox(keypair.Value.ToString)
                Case "peers"
                    If TypeOf keypair.Value Is BEncodedList Then
                        peers.AddRange(Peer.Decode(DirectCast(keypair.Value, BEncodedList)))
                    ElseIf TypeOf keypair.Value Is BEncodedString Then
                        peers.AddRange(Peer.Decode(DirectCast(keypair.Value, BEncodedString)))
                    End If
                Case Else
                    'MsgBox("HttpTracker - Unknown announce tag received:" & keypair.Key.ToString() & keypair.Value.ToString())
            End Select
        Next

        Return peers
    End Function

    ''' <summary>
    ''' Original CreateAnnounceString is private only and we need to modify it a little bit; this the old one out of svn
    ''' they have created here a better function that uses UriQueryBuilder but its oversized here
    ''' 
    ''' MonoTorrent.Client.Tracker.HTTPTracker.CreateAnnounceString
    ''' http://anonsvn.mono-project.com/viewvc/trunk/bitsharp/src/MonoTorrent/MonoTorrent.Client/Tracker/HTTPTracker.cs?revision=141866
    ''' </summary>
    ''' <param name="parameters"></param>
    ''' <param name="Uri">AnnounceURL of the TorrentFile</param>
    ''' <param name="Key">a radon key paramter</param>
    ''' <returns>url to use with a WebRequest</returns>
    ''' <remarks></remarks>
    Private Function CreateAnnounceString(ByVal parameters As AnnounceParameters, ByVal Uri As String, ByVal Key As String) As String
        Dim sb As New System.Text.StringBuilder(256)

        'base.LastUpdated = DateTime.Now;
        ' FIXME: This method should be tidied up. I don't like the way it current works
        sb.Append(Uri)
        sb.Append(If(Uri.Contains("?"), "&"c, "?"c))
        sb.Append("info_hash=")
        sb.Append(parameters.InfoHash.UrlEncode())
        sb.Append("&peer_id=")
        sb.Append(parameters.PeerId)
        sb.Append("&port=")
        sb.Append(parameters.Port)
        If parameters.SupportsEncryption Then
            sb.Append("&supportcrypto=1")
        End If
        If parameters.RequireEncryption Then
            sb.Append("&requirecrypto=1")
        End If
        sb.Append("&uploaded=")
        sb.Append(parameters.BytesUploaded)
        sb.Append("&downloaded=")
        sb.Append(parameters.BytesDownloaded)
        sb.Append("&left=")
        sb.Append(parameters.BytesLeft)
        sb.Append("&compact=1")
        ' Always use compact response
        sb.Append("&numwant=")
        sb.Append(100)
        If Not Uri.Contains("&key=") AndAlso Not Uri.Contains("?key=") Then
            sb.Append("&key=")
            ' The 'key' protocol, used as a kind of 'password'. Must be the same between announces
            sb.Append(Key)
        End If
        If parameters.Ipaddress IsNot Nothing Then
            sb.Append("&ip=")
            sb.Append(parameters.Ipaddress)
        End If

        ' If we have not successfully sent the started event to this tier, override the passed in started event
        ' Otherwise append the event if it is not "none"
        'if (!parameters.Id.Tracker.Tier.SentStartedEvent)
        '
        '    sb.Append("&event=started");
        '    parameters.Id.Tracker.Tier.SendingStartedEvent = true;
        '
        If parameters.ClientEvent <> TorrentEvent.None Then
            sb.Append("&event=")
            sb.Append(parameters.ClientEvent.ToString().ToLower())
        End If


        Return sb.ToString()
    End Function
    ''' <summary>
    ''' HttpWebResponse and GetResponseStream dont gives use a full readable stream so we must convert it
    ''' 
    ''' Look at: MonoTorrent.Client.Tracker.HTTPTracker.DecodeResponse
    ''' http://anonsvn.mono-project.com/viewvc/trunk/bitsharp/src/MonoTorrent/MonoTorrent.Client/Tracker/HTTPTracker.cs
    ''' or
    ''' http://bytes.com/topic/c-sharp/answers/232436-download-binary-file-http#post949811
    ''' </summary>
    ''' <param name="response"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Function WebResponseToStream(ByVal response As HttpWebResponse) As Stream

        Dim responseStream As Stream = response.GetResponseStream
        Dim fs As MemoryStream = New MemoryStream(256)

        Dim buffer As Byte() = New Byte(4095) 
        Dim length As Integer = responseStream.Read(buffer, 0, 4096)

        While length > 0
            fs.Write(buffer, 0, length)
            length = responseStream.Read(buffer, 0, 4096)
        End While

        fs.Seek(0, SeekOrigin.Begin)

        Return fs
    End Function
End Module

问题只出现在加载文件.torrent部分:

Dim TorrentFile As **torrent** = ("D:\youtorrent.torrent")

Vb.net 向我抛出“在文本 torrent 上键入预期的错误。有任何解决方案吗?谢谢大家!

【问题讨论】:

【参考方案1】:

试试

Dim TorrentFile As torrent = Torrent.Load("D:\youtorrent.torrent")

【讨论】:

我相信它会引发该错误,因为您的 vb.net 项目针对的 .NET 框架与您引用的 Monotorrent dll 不同。我测试了一个项目并看到了同样的问题,然后将我的 vb 项目切换到目标 .NET 2.0 并且它可以识别它。 我在更改为 NET 2.0 版后遇到了同样的问题:i.imgur.com/DGvj0t2.png 您的 MonoTorrent 导入是否突出显示为无法识别或未被使用?如果您删除导入,然后将它们添加回来,它似乎在您运行之前识别它,然后再次出错?如果这些问题中的任何一个都是“是”,那么这与 dll 不被识别为兼容有关。 MonoTorrent 参考的“复制本地”设置为 True 还是 False? 你说得对,我又开始为 .NET 2.0 做项目了,现在一切似乎都很完美,但代码似乎没有下载任何 .torrent 文件

以上是关于使用 Monotorrent 在 VB.NET 中加载 Torrent的主要内容,如果未能解决你的问题,请参考以下文章

Monotorrent 传输文件

无法使用 monotorrent 从新创建的 torrent 下载文件

使用 monotorrent c# 创建 torrent

monotorrent - writeRate/readRate 不工作

Monotorrent 示例客户端不要下载一些种子

写入时的 MonoTorrent 事件