1

基本上我正在尝试从 udp 种子跟踪器中获取 php 中的同行。目的是分析不同地区的流量。

所以我不需要下载种子,只需获取对等列表并再次宣布即可获得不同的集合。我尝试使用 PHP

我选择了一个开源代码,它可以抓取 udp 种子并对其进行修改。

这是代码

require_once(dirname(__FILE__) . '/tscraper.php');

class udptscraper extends tscraper{

    /*  $url: Tracker url like: udp://tracker.tld:port or udp://tracker.tld:port/announce
        $infohash: Infohash string or array (max 74 items). 40 char long infohash. 
        */
    public function scrape($url,$infohash){
        if(!is_array($infohash)){ $infohash = array($infohash); }
        foreach($infohash as $hash){
            if(!preg_match('#^[a-f0-9]{40}$#i',$hash)){ throw new ScraperException('Invalid infohash: ' . $hash . '.'); }
        }
        if(count($infohash) > 74){ throw new ScraperException('Too many infohashes provided.'); }
        if(!preg_match('%udp://([^:/]*)(?::([0-9]*))?(?:/)?%si', $url, $m)){ throw new ScraperException('Invalid tracker url.'); }
        $tracker = 'udp://' . $m[1];
        $port = isset($m[2]) ? $m[2] : 80;
        $transaction_id = mt_rand(0,65535);
        $fp = fsockopen($tracker, $port, $errno, $errstr);
        if(!$fp){ throw new ScraperException('Could not open UDP connection: ' . $errno . ' - ' . $errstr,0,true); }
        stream_set_timeout($fp, $this->timeout);

        $current_connid = "\x00\x00\x04\x17\x27\x10\x19\x80";

        //Connection request
        $packet = $current_connid . pack("N", 0) . pack("N", $transaction_id);
        fwrite($fp,$packet);

        //Connection response
        $ret = fread($fp, 16);
        if(strlen($ret) < 1){ throw new ScraperException('No connection response.',0,true); }
        if(strlen($ret) < 16){ throw new ScraperException('Too short connection response.'); }
        $retd = unpack("Naction/Ntransid",$ret);
        if($retd['action'] != 0 || $retd['transid'] != $transaction_id){
            throw new ScraperException('Invalid connection response.');
        }
        $current_connid = substr($ret,8,8);

        //ANNOUNCE request
        $hashes = '';
        $pid ='O5214m2Y0z6178K1z090';
        $key = mt_rand(0,65535);
        $down =mt_rand(0,12345);
        $left =mt_rand(0,12345);
        $upped =mt_rand(0,12345);
        $transaction_id = mt_rand(0,65535);
        $event = 2;
        $socket = socket_create_listen (19624);

        foreach($infohash as $hash){ $hashes .= pack('H*', $hash); }
        $packet = $current_connid . pack("N", 1) . pack("N", $transaction_id) . $hashes . pack("N", $pid) . pack("N", $down) . pack("N", $left) . pack("N", $upped) . pack("N", 0) . pack("N", 0) . pack("N", $key) . pack("N", -1) . pack("N", 19624);
        fwrite($fp,$packet);

        //ANNOUNCE response
        $readlength = 20 + (6 * count($infohash));
        $ret = fread($fp, $readlength);
        echo $ret;
        if(strlen($ret) < 1){ throw new ScraperException('No .',0,true); }
        if(strlen($ret) < 8){ throw new ScraperException('Too short  response.'); }
        $retd = unpack("Naction/Ntransid",$ret);
        // Todo check for error string if response = 3
        if($retd['action'] != 1 || $retd['transid'] != $transaction_id){
            throw new ScraperException('Invalid scrape response.');
        }
        if(strlen($ret) < $readlength){ throw new ScraperException('Too short scrape response.'); }
        $torrents = array();
        $index = 8;
        foreach($infohash as $hash){
            $retd = unpack("Ninterval/Nleechers/Nseeders/Nipaddr/NTCP",substr($ret,$index));
            print_r($retd);
            $retd['infohash'] = $hash;
            $torrents[$hash] = $retd;
            $index = $index + 12;
        }

        return($torrents);
    }
}





try{
        $timeout = 2;

        $scraper = new udptscraper($timeout);
        $ret = $scraper->scrape('udp://tracker.openbittorrent.com:80/announce',array('8B60D5838A2CE34294AF9E49FF990C5BEC6C61B1'));

        //print_r($ret);
    }catch(ScraperException $e){
        echo('Error: ' . $e->getMessage() . "<br />\n");
        echo('Connection error: ' . ($e->isConnectionError() ? 'yes' : 'no') . "<br />\n");
    }

?>

我只使用了 1 个 HASH 值 请大家帮忙。

4

1 回答 1

0

EDIT : The tracker server sometimes send the response message with peer list of peers replaced by a 6 bytes per peer. The first 4 bytes are the host IP, and the last 2bytes are port number. You should parse them to communicate with peers for pieces.

I think theory(specs) is probably not a fact. all specs about Bittorent from Internet become outdated. It might be impossible to check whether announce request is correct by just following the spec.
I recommend you to try using Wireshark. Capture packets that common Bittorent-client sends, and then check how common Bittornet client works. Compare announce request that your php code send, to one common client sends.

Actually, I'm trying to implement Bittorent client in C. I had a hard time communicating with a tracker server, since not specifying compact field in request message. But most specs says compact field in announce request is optional.

Try using wireshark. then compare two requests(your request and the other that common bittorent sends.) enter image description here

于 2013-07-03T06:17:23.973 回答