php dht,dht.php

// 文件路径

define('ABSPATH', dirname(__FILE__));

// 主进程数, 一般为CPU的1至4倍

define('WORKER_NUM', 2);

// 允许最大连接数, 不可大于系统ulimit -n的值

define('MAX_REQUEST', 1000);

// 线程数

define('MAX_PROCESS', 10);

// 自动查找间隔, 单位为毫秒

define('AUTO_FIND_TIME', 10000);

// 发送find_node间隔, 单位秒

define('NEXT_FIND_NODE_TIME', 0.5);

// 载入类文件

require_once ABSPATH . '/inc/Node.class.php';

require_once ABSPATH . '/inc/Bencode.class.php';

require_once ABSPATH .'/inc/Base.class.php';

// 保存swoole_server对象

$serv = NULL;

// 设置自身node id

$nid = Base::get_node_id();

// 初始化路由器

$table = array();

// 最后请求时间

$last_find = time();

// 保存线程列表

$threads = [];

// 长期在线node

$bootstrap_nodes = array(

array('router.bittorrent.com', 6881),

array('dht.transmissionbt.com', 6881),

array('router.utorrent.com', 6881)

);

write(date('Y-m-d H:i:s', time()) . " - 服务启动...\n");

$serv = new swoole_server('0.0.0.0', 6882, SWOOLE_PROCESS, SWOOLE_SOCK_UDP);

$serv->set(array(

'worker_num' => WORKER_NUM,

'daemonize' => true,

'max_request' => MAX_REQUEST,

'dispatch_mode' => 2,

'log_file' => ABSPATH . 'error.log'

));

$serv->on('WorkerStart', function($serv, $worker_id){

// 添加一个定时器, 使服务器定时寻找节点

$serv->addtimer(AUTO_FIND_TIME);

auto_find_node();

});

$serv->on('Receive', function($serv, $fd, $from_id, $data){

// 检查数据长度

if(strlen($data) == 0)

return false;

// 对数据进行解码

$msg = Base::decode($data);

// 获取对端链接信息

$fdinfo = $serv->connection_info($fd, $from_id);

// 对接收到的数据进行类型判断

if($msg['y'] == 'r'){

// 如果是回复, 且包含nodes信息

if(array_key_exists('nodes', $msg['r']))

// 对nodes进行操作

response_action($msg, array($fdinfo['remote_ip'], $fdinfo['remote_port']));

}elseif($msg['y'] == 'q'){

// 如果是请求, 则执行请求判断

request_action($msg, array($fdinfo['remote_ip'], $fdinfo['remote_port']));

}else{

return false;

}

});

$serv->on('Timer', function($interval){

for($i=0; $i

$process = new swoole_process(function(){

auto_find_node();

});

$pid = $process->start();

$threads[$pid] = $process;

swoole_process::wait();

}

});

$serv->start();

/**

* 自动查找节点方法, 将在DHT网络中自动搜寻节点信息

* @return void

*/

function auto_find_node(){

global $table;

// 如果路由表中没有数据则先加入DHT网络

if(count($table) == 0)

return join_dht();

// 循环处理路由表

while(count($table)){

// 从路由表中删除第一个node并返回被删除的node

$node = array_shift($table);

// 发送查找find_node到node中

find_node(array($node->ip, $node->port), $node->nid);

sleep(0.005);

}

}

/**

* 加入dht网络

* @return void

*/

function join_dht(){

global $table, $bootstrap_nodes;

// 循环操作

foreach($bootstrap_nodes as $node){

// 将node域名解析为IP地址, 并发送find_node请求

find_node(array(gethostbyname($node[0]), $node[1]));

}

}

/**

* 发送find_node请求

* @param array $address 对端链接信息

* @param string $id node id

* @return void

*/

function find_node($address, $id = null){

global $nid, $table;

// 若未指定id则使用自身node id

if(is_null($id))

$mid = $nid;

else

// 否则伪造一个相邻id

$mid = Base::get_neighbor($id, $nid);

// 定义发送数据

$msg = array(

't' => Base::entropy(2),

'y' => 'q',

'q' => 'find_node',

'a' => array(

'id' => $nid,

'target' => $mid

)

);

// 发送请求数据到对端

send_response($msg, $address);

}

/**

* 处理对端发来的请求

* @param array $msg 接收到的请求数据

* @param array $address 对端链接信息

* @return void

*/

function request_action($msg, $address){

switch($msg['q']){

case 'ping':

on_ping($msg, $address);

break;

case 'find_node':

on_find_node($msg, $address);

break;

case 'get_peers':

// 处理get_peers请求

on_get_peers($msg, $address);

break;

case 'announce_peer':

// 处理announce_peer请求

on_announce_peer($msg, $address);

break;

default:

return false;

}

}

/**

* 处理接收到的find_node回复

* @param array $msg 接收到的数据

* @param array $address 对端链接信息

* @return void

*/

function response_action($msg, $address){

// 先检查接收到的信息是否正确

if(!isset($msg['r']['nodes']) || !isset($msg['r']['nodes'][1]))

return false;

// 对nodes数据进行解码

$nodes = Base::decode_nodes($msg['r']['nodes']);

// 对nodes循环处理

foreach($nodes as $node){

// 将node加入到路由表中

append($node);

}

}

/**

* 处理ping请求

* @param array $msg 接收到的ping请求数据

* @param array $address 对端链接信息

* @return void

*/

function on_ping($msg, $address){

global $nid;

// 获取对端node id

$id = $msg['a']['id'];

// 生成回复数据

$msg = array(

't' => $msg['t'],

'y' => 'r',

'r' => array(

'id' => $nid

)

);

// 将node加入路由表

append(new Node($id, $address[0], $address[1]));

// 发送回复数据

send_response($msg, $address);

}

/**

* 处理find_node请求

* @param array $msg 接收到的find_node请求数据

* @param array $address 对端链接信息

* @return void

*/

function on_find_node($msg, $address){

global $nid;

// 获取node列表

$nodes = get_nodes(16);

// 获取对端node id

$id = $msg['a']['id'];

// 生成回复数据

$msg = array(

't' => $msg['t'],

'y' => 'r',

'r' => array(

'id' => $nid,

'nodes' => Base::encode_nodes($nodes)

)

);

// 将node加入路由表

append(new Node($id, $address[0], $address[1]));

// 发送回复数据

send_response($msg, $address);

}

/**

* 处理get_peers请求

* @param array $msg 接收到的get_peers请求数据

* @param array $address 对端链接信息

* @return void

*/

function on_get_peers($msg, $address){

global $nid;

// 获取info_hash信息

$infohash = $msg['a']['info_hash'];

// 获取node id

$id = $msg['a']['id'];

// 生成回复数据

$msg = array(

't' => $msg['t'],

'y' => 'r',

'r' => array(

'id' => $nid,

'nodes' => Base::encode_nodes(get_nodes()),

'token' => substr($infohash, 0, 2)

)

);

// 将node加入路由表

append(new Node($id, $address[0], $address[1]));

// 向对端发送回复数据

send_response($msg, $address);

}

/**

* 处理announce_peer请求

* @param array $msg 接收到的announce_peer请求数据

* @param array $address 对端链接信息

* @return void

*/

function on_announce_peer($msg, $address){

global $nid;

// 获取infohash

$infohash = $msg['a']['info_hash'];

// 获取token

$token = $msg['a']['token'];

// 获取node id

$id = $msg['a']['id'];

// 验证token是否正确

if(substr($infohash, 0, 2) == $token){

/*$txt = array(

'action' => 'announce_peer',

'msg' => array(

'ip' => $address[0],

'port1' => $address[1],

'port2' => $msg['a']['port'],

'infohash' => $infohash

)

);

var_dump($txt);*/

write(date('Y-m-d H:i:s', time()) . " 获取到info_hash: " . strtoupper(bin2hex($infohash)) . "\n");

}

// 生成回复数据

$msg = array(

't' => $msg['t'],

'y' => 'r',

'r' => array(

'id' => $nid

)

);

// 发送请求回复

send_response($msg, $address);

}

/**

* 向对端发送数据

* @param array $msg 要发送的数据

* @param array $address 对端链接信息

* @return void

*/

function send_response($msg, $address){

global $serv;

$serv->sendto($address[0], $address[1], Base::encode($msg));

}

/**

* 添加node到路由表

* @param Node $node node模型

* @return boolean 是否添加成功

*/

function append($node){

global $nid, $table;

// 检查node id是否正确

if(!isset($node->nid[19]))

return false;

// 检查是否为自身node id

if($node->nid == $nid)

return false;

// 检查node是否已存在

if(in_array($node, $table))

return false;

// 如果路由表中的项达到200时, 删除第一项

if(count($table) >= 200)

array_shift($table);

return array_push($table, $node);

}

function get_nodes($len = 8){

global $table;

if(count($table) <= $len)

return $table;

$nodes = array();

for($i=0; $i

$nodes[] = $table[mt_rand(0, count($table) - 1)];

}

return $nodes;

}

/**

* 将数据写入文件

* @param string $msg 要写入文件的数据

* @return void

*/

function write($msg){

$fp = fopen('./infohash.log', 'ab');

fwrite($fp, $msg);

fclose($fp);

}

一键复制

编辑

Web IDE

原始数据

按行查看

历史

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值