dht协议实现

上一篇完成了路由表的实现,建立了路由表后,我们还要对路由表进行初始化,因为一开始路由表为空,所以我们需要借助一些知名的dht网络中的节点,对这些节点进行find_node,然后一步步初始化路由表。这里我们选dht.transmissionbt.com来进行初始化。在dht网络都是使用upd协议进行数据的传输,所以我们需要开启一个upd端口,这里使用netty来做通信框架。这里我们主要来看怎么发送find_node

/**
* find_node
* @param node 自己的id
* @param target 目标id
* @param address 请求地址
* @param num channel号
*/
public void findNode(String node,String target,InetSocketAddress address,int num){
if(!channels.get(num).isWritable()){
return;
}
FindNodeRequest findNodeRequest=new FindNodeRequest(node,target);
channels.get(num).writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(bencode.encode(DHTUtil.beanToMap(findNodeRequest))), address));
}

FindNodeRequest 主要有哪些字段

@Data
@AllArgsConstructor()
public class BaseRequest { private String t;//messageid 2 byte private String y;//"q" for query, "r" for response, or "e" for error private String q;//method ping/find_node/get_peers/announce_peer //private String v;//client identifier registered in BEP 20 这里不管这个
}
public class FindNodeRequest extends BaseRequest{
private FindNodeRequestContent a=new FindNodeRequestContent(); @Data
@Accessors(chain = true)
private static class FindNodeRequestContent{
private String id;
private String target;
} public FindNodeRequest(String id,String target){
super(DHTUtil.generateMessageId(),
MessageTypeEnmu.QUERY.getKey(),
MethodEnmu.FIND_NODE.getKey());
a.id=id;
a.target=target;
} public static void main(String[] args) {
FindNodeRequest f=new FindNodeRequest("df","23");
}
}

find_node返回结果后,会对其进行bencoded解码最后解析成ProcessDto对象,接下来我们来看怎么处理返回结果

@Override
public void activeProcess(ProcessDto processDto) {
Map<String, Object> rMap = DHTUtil.getParamMap(processDto.getRawMap(), "r", "FIND_NODE,找不到r参数.map:" + processDto.getRawMap());
List<Node> nodeList = DHTUtil.getNodeListByRMap(rMap);
//为空退出
if (CollectionUtils.isEmpty(nodeList)) return;
//去重
Node[] nodes = nodeList.stream().distinct().toArray(Node[]::new);
//将nodes加入发送队列继续find_node
for (Node node : nodes) {
FileUtil.wirteNode("nodes1=="+node.getIp()+","+node.getPort()+"\r\n");
findNodeTask.put(node.toAddress());
}
byte[] id = DHTUtil.getParamString(rMap, "id", "FIND_NODE,找不到id参数.map:" + processDto.getRawMap()).getBytes(CharsetUtil.ISO_8859_1);
//将发送消息的节点加入路由表
routingTables.get(processDto.getNum()).put(new Node(id, processDto.getSender(), NodeRankEnum.FIND_NODE_RECEIVE.getKey()));
}

建立路由表的进行find_node的时候,对方也会保存我们的信息到他们的路由表所以我们只需要实现ping用来回应自己一直在线。最后获取infohash最主要的是

get_peers和announce_peer分别对应GetPeersRequest和AnnoucePeersRequest,发送方式也处理方式也类似,可以参考一下源码https://github.com/mistletoe9527/dht-spider

好了,现在已经可以通过dht网络获取到infohash了,但是只有infohash还不够,因为还需要获取种子的metadata,这样才能知道这个infohash对应的种子所对应的文件。只有建立起文件和infohash的对应关系,我们才能提供搜索,下一篇会介绍怎么从dht网络中获取种子的infohash。

如何用java实现一个p2p种子搜索(3)-dht协议实现的更多相关文章

  1. 如何用java实现一个p2p种子搜索(1)-概念

    前言 说句大实话,网上介绍怎么用java实现p2p种子的搜索这种资料不是特别多,大部分都是python的,用python的话就会简单很多,它里面有很多简单方便的包,libtorrent等等,当然你用这 ...

  2. 如何用java实现一个p2p种子搜索(4)-种子获取

    种子获取 在上一篇中我们已经可以获取到dht网络中的infohash了,所以我们只需要通过infohash来获取到种子,最后获取种子里面的文件名,然后和获取到的infohash建立对应关系,那么我们的 ...

  3. 如何用java实现一个p2p种子搜索(2)-路由表实现

    路由表实现 回顾一下上一篇讲的内容,上一篇提到从dht网络中获取infohash,那么加入dht网络后的最重要的第一步就是怎么去建立路由表. 路由表里面保存的是dht中其他node的信息,所以node ...

  4. 如何用java创建一个jdbc程序

    第一个jdbc程序 JDBC简介 Java数据库连接(Java Database Connectivity,JDBC),是一种用于执行SQL语句的Java API,它由一组用Java编程语言编写的类和 ...

  5. 如何用java完成一个中文词频统计程序

    要想完成一个中文词频统计功能,首先必须使用一个中文分词器,这里使用的是中科院的.下载地址是http://ictclas.nlpir.org/downloads,由于本人电脑系统是win32位的,因此下 ...

  6. 一个支持种子、磁力、迅雷下载和磁力搜索的APP源代码

    磁力搜索网站2020/01/12更新 https://www.cnblogs.com/cilisousuo/p/12099547.html 一个支持种子.磁力.迅雷下载和磁力搜索的APP源代码 Lic ...

  7. 如何用Java编写一段代码引发内存泄露

    本文来自StackOverflow问答网站的一个热门讨论:如何用Java编写一段会发生内存泄露的代码. Q:刚才我参加了面试,面试官问我如何写出会发生内存泄露的Java代码.这个问题我一点思路都没有, ...

  8. 五:用JAVA写一个阿里云VPC Open API调用程序

    用JAVA写一个阿里云VPC Open API调用程序 摘要:用JAVA拼出来Open API的URL 引言 VPC提供了丰富的API接口,让网络工程是可以通过API调用的方式管理网络资源.用程序和软 ...

  9. 基于python的种子搜索网站-开发过程

    本讲会对种子搜索网站的开发过程进行详细的讲解. 源码地址:https://github.com/geeeeeeeek/bt 项目开发过程 项目简介 该项目是基于python的web类库django开发 ...

随机推荐

  1. 五、Redis持久化配置

    转载:[https://www.cnblogs.com/xingzc/p/5988080.html] Redis提供的持久化机制(RDB和AOF) Redis提供的持久化机制 Redis是一种面向“k ...

  2. C#中字符串转日期类型

    1,yyyyMMdd DateTime date = DateTime.ParseExact(", "yyyyMMdd", System.Globalization.Cu ...

  3. sql中检查时间是否重叠

    先画一个时间轴,方便理解. 设新的时间块,开始时间为@BeginDate,结束时间为@EndDate.数据库中的数据为BeginDate和EndDate 这样可以直观的看出来,新的时间块插入进来,只需 ...

  4. 利用ir.sequence自动生成序列号

    利用ir.sequence自动生成序列号 什么是序列号 可以这么理解,我有一个产品序号,编码的前缀是SOP,后缀是0001~9999的序号,没生成一个产品就自动流水加一,序列号不会重复,odoo中的i ...

  5. THUWC2019 游记

    DAY1 开场先看 t1,发现答案的分子就是 \(\sum_i\) 颜色 \(i\) 在 A 中的出现次数乘上颜色 \(i\) 在 B 中的出现次数,分母就是 B 的长度,就去写了一个按颜色的出现次数 ...

  6. Go中的iota

    当时在学习Iota这个知识点的时候仅仅是一笔掠过,比如这种 const( a=iota b c ) 一眼看出他怎么使用的时候就觉得自己已经懂得了 再到后来看到这样的例子 const( a = 5*io ...

  7. 「雅礼集训 2017 Day5」珠宝

    题目描述 Miranda 准备去市里最有名的珠宝展览会,展览会有可以购买珠宝,但可惜的是只能现金支付,Miranda 十分纠结究竟要带多少的现金,假如现金带多了,就会比较危险,假如带少了,看到想买的右 ...

  8. 一加X 手机变砖过程

    很久无使用的一台手机,因需要获得ROOT权限而使用kingroot这款软件,无法获得root权限.而这个软件会导致手机无法进入ERCOVERY模式,后果是你没有办法刷入别的rom,而kingroot的 ...

  9. django 4.get接口开发

    根据上一篇文章,有post,那么就有get请求,其余部分不变,就是把post换成get就可以. #views.py from django.http.response import HttpRespo ...

  10. jQuery 为动态添加的元素绑定事件

    在使用jquery的方式为元素绑定事件时,我经常使用bind或者click,但这只能为页面已经加载好的元素绑定事件.像需要用ajax的方式请求远程数据来动态添加页面元素时,显然以上几种绑定事件的方式是 ...