JXTA探索:双向管道(Bi-directional Pipe)的实现和原理剖析

JXTA探索:双向管道(Bi-directional Pipe)的实现和原理剖析
发布时间:2006.03.09 23:59     来源:CSDN    作者:

 

jxta探索:双向管道(Bi-directional Pipe)的实现和原理剖析

 


*
什么是管道(Pipe)

 

管道是jxta里面比较重要的一个概念。管道是Peer之间的虚拟通道。通常,我们认为对等通信是单个的通信连接。但是也并不是总是这样的。因为防火墙、NAT和其它障碍的存在,许多Peer并不能直接连接。这时,管道更像一个在多种通信协议之上的虚拟层,可以通过起网关作用的Peer对通信提供中继支持。

 

    使用它的好处在于,不用去关心Peer所使用的真正的地址和协议是什么,使用抽象出来的管道,可以为P2P应用提供强大的功能并降低复杂性。

 


*
为什么要分析双向管道的实现原理?

 

     在JXTA的J2SE参考实现中,提供了三种最基本类型的管道,它们分别是:

 

    a 单向管道(UnicastType)

 

    b 单向安全管道(UnicastSecureType)

 

    c 广播管道(PropagateType)

 

    而实际应用中,可以通过基本类型的管道的组合形成一些更有用的类型,如双向管道(Bi-directional Pipe)。因为我们知道在P2P应用中,如聊天,传送文件等操作都需要实现双向管道。在JXTA的J2SE参考实现中提供了两个有用的类(JxtaBidiPipe和JxtaServerPipe),通过一种巧妙的机制,实现了一个双向管道。

 

尽管在使用双向管道时,不需要了解内部的实现方法,但是我认为理解双向管道的实现机理对于使用双向管道有一定的帮助,对于进一步分析jxta也是有益的,希望通过下面的分析,能给jxta应用的开发者一些有益的提示,同时也作为本人的一个参考。

 

      因为jxta在推出后一直在不断的发展中,2.0和1.0版本之间出现了很多的不一致,因此声明,本文列出的代码均基于最新的JXTA2.0 API,在Jxta的J2SE参考实现2.3.1版本上调试通过。

 


*
用JXTA建立双向管道的过程

 

 编写一个双向管道的应用程序需要用到如下两个类:JxtaBidiPipe和JxtaServerPipe,它们共同实现了一个握手协议,即 使用一个由连接双方共同填写的结构化xml文档,在jxta里用Message来描述这个文档, 该Message有以下内容

 

<Credential>决定请求者是否有获得连接的权利<Credential>

 

<reqPipe>请求者的管道广告(pipe advertisement)</reqPipe>

 

<remPipe>远程的管道广告(remote pipe advertisement)</remPipe>

 

<remPeer> 远程的节点广告(remote peer advertisement)</remPeer>

 

<reliable> 是否可靠性连接 ("true", or "false") </reliable>

 

<data> 通讯数据 <data>

 

   而实际建立和使用双向管道的过程中,并不需要了解这个Message的,这里只是为后面分析建立的原理作准备。

 

  我们知道,即使是在P2P系统中,也有一个连接发起节点(这里设定为PeerA),和一个连接接受节点 (这里假定为PeerB)

 

首先在发起节点A在程序当中使用如下语句发起JxtaBidiPipe连接:

 

try {

 

    FileInputStream is = new FileInputStream("pipe.adv");

 

    eg.pipeAdv =

 

 (PipeAdvertisement)AdvertisementFactory.newAdvertisement(MimeMediaType.XMLUTF8, is);

 

    is.close();

 

    System.out.println("creating the BiDi pipe");

 

    eg.pipe = new JxtaBiDiPipe();

 

    eg.pipe.connect(eg.netPeerGroup,

 

                    null,

 

                    eg.pipeAdv,

 

                    180000,

 

                    // register as a message listener

 

                    eg);

 

} catch (Exception e) {

 

    System.out.println("failed to read/parse pipe advertisement");

 

    e.printStackTrace();

 

    System.exit(-1);

 

}

 

 

 

在节点B处用如下方法响应这个连接:(这里用到了JxtaServerPipe,这是一个辅助类,它的行为非常类似JDK开发中常用的类ServerSocket)

 

try {

 

    FileInputStream is = new FileInputStream("pipe.adv");

 

    eg.pipeAdv =

 

(PipeAdvertisement) AdvertisementFactory.newAdvertisement(MimeMediaType.XMLUTF8, is);

 

    is.close();

 

    eg.serverPipe = new JxtaServerPipe(eg.netPeerGroup, eg.pipeAdv);

 

    // we want to block until a connection is established

 

    eg.serverPipe.setPipeTimeout(0);

 

    JxtaBiDiPipe bipipe = serverPipe.accept();

 

    if (bipipe != null ) {

 

           System.out.println("BiDi Pipe created");

 

        receiveAndSendTestMessage(bipipe);

 

    }

 

} catch (Exception e) {

 

    System.out.println("failed to read/parse pipe advertisement");

 

    e.printStackTrace();

 

    System.exit(-1);

 

}

 

 

 

建立了双向管道的连接后,就可以进行简单的通讯了。

 

注意到,这里JxtaBidiPipe和JxtaServerPipe的行为非常类似JDK里面的Socket和ServerSocket。我想这是JXTA的设计者有意为之,目的是使得Java开发者更方便的使用这些类。

 

 

 

* jxta 双向连接对象(JxtaBidiPipe类型对象)的使用

 

可以用isBound()来判断出JxtaBidiPipe对象的双向连接是否建立。

 

可以用getMessage()来接收JxtaBidiPipe上的消息。

 

可以用sendMessage()在JxtaBidiPipe上发送消息。

 

 

 

* 双向管道建立的原理的源代码剖析

 

    在分析之前,现分析一下jxta里面一个单向管道的大致建立过程,因为双向管道实际上就是两个双向管道的组合。

 

   单向管道的建立过程比较简单(以两个节点PeerA和PeerB为例)

 

   (1)首先PeerA根据一个管道的广告建立一个输入管道(Input Pipe) 等待连接;

 

   (2)PeerB根据同样的广告建立一个输出管道(Output Pipe);

 

   (3)如果PeerB的输出管道建立成功,则PeerB会收到相应的连接已经建立的提示(通过响应outputPipeEvent),这时一个从B到A的单向连接就建立起来了,在A中可以通过响应pipeMsgEvent来得到B发送过来的消息的提示,并得到消息的内容。

 

   

 

    这样实现的一个单向管道除了只能单向传输外,还有一个显著的缺点在于它要求通信双方必须使用一个共同的管道广告(广告一般用一个组内发布的xml文档来表示),而且在双方发送消息的时候,该文档定义的管道广告一直被使用,不能再用来建立新的连接。

 

    如果按照一般的思路,建立双向管道就需要使用两个共用的管道广告,并在双向通信过程中一直占用这两个管道广告。

 

 而实际上,JXTA里面实现的双向管道,只在初始时使用了一个共用的管道广告PublicPipeA2B advertisement(可以考虑使用组内的服务实现),而后通过巧妙的机制,建立了两个内部使用的管道广告(即不用发布, 分别为privatePipeB2A和privatePipeA2B的advertisement),并用这两个内部管道广告实现了双向通信,并且通信建立以后,原先的共用的管道广告对于该通信过程就无用了,还可以被别的通信管道再次利用。

 

 

 

    下面按照时间顺序,分析一个双向管道的建立过程:(序号后面的字母表明是在哪个节点进行,如”1B”表示该动作发生在Peer B)

 

    (1B)节点B处新建一个JxtaServerPipe对象,JxtaServerPipe本身是一个InputPipe, 在它构造的时候使用共用的广告,即publicPipeA2B的advertisement建立一个输入管道等待连接。

 

    (2A) 节点A新建立一个输入管道Inputpipe(就是privatePipeB2A), 并将这个管道的广告,即privatePipeB2A的advertisement封装到一个消息Message里, 这个Message的消息一共填写了Credential, reqPipe, remPeer, reliable四个部分,我们这里只关注reqPipe部分,这里存放的就是广告privatePipeB2A advertisement(参照JxtaBidiPipe的createOpenMessage方法)

 

    (3A) 节点A用publicPipeA2B的advertisement来建立输出管道OutputPipe ,这样就与节点B建立了一个AàB的单向连接。 连接建立以后, 马上把第(2A)步产生的Message用这个管道publicPipeA2B发送给B, 然后又进入等待。(参照JxtaBidiPipe的connect方法)

 

    (4B) 节点B用上面第(2a)步里面接受的Message里包含的reqPipe部分的pipe advertisement建立一个OutputPipe(就是PrivatePipeB2A), 这时就会连接到上面在第(2A)步建立的PrivatePipeB2A的InputPipe上, 到这一步就建立了一个B到A的内部连接管道privatePipeB2A。(参照JxtaServerPipe的processMessage方法)

 

    (5B) 节点B新建立一个InputPipe(就是privatePipeA2B的输入管道), 并把Message的remPeer部分填写上这个新建立的管道的广告,即privatePipeA2B的advertisement,(实际上填写了Credential, remPipe, remPeer三个部分,我们这里只关注remPeer部分),用第(4B)步建立的连接管道PrivatePipeB2A把这个填写好的Message发回给节点A。(参照JxtaServerPipe的processMessage和sendResponseMessage方法)

 

    (6A) 节点A处接收到这个消息后马上用这个remPeer部分包含的privatePipeA2B 的advertisement建立一个输出管道OutputPipe。到这一步就建立了一个新的A到B的连接管道privatePipeA2B,而先前建立的A到B的管道publicPipeA2B就可以不用继续使用了,然后结束第(3A)步的等待,这时一个包含privatePipeA2B和privatePipeB2A的双向管道,即一个JxtaBidiPipe对象就正式建立(绑定)成功了。

 

 

 

*结束语

 

还有一对JXTA的类JxtaSocket和JxtaServerSocket,实现的机理和上面的方法大致类似,根据JXTA开发者的说法,JxtaBidiPipe和JxtaServerPipe适用于小数据量应用,如即时消息,聊天信息等;而JxtaSocket和JxtaServerSocket适用于大数据量的通信,如文件传输等。我将在下一篇里分析JxtaSocket和JxtaServerSocket的例子。

 

 

 

 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 目标检测的定义 目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标(物体),确定它们的类别和位置,是计算机视觉领域的核心问题之一。由于各类物体有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具有挑战性的问题。 目标检测任务可分为两个关键的子任务,目标定位和目标分类。首先检测图像中目标的位置(目标定位),然后给出每个目标的具体类别(目标分类)。输出结果是一个边界框(称为Bounding-box,一般形式为(x1,y1,x2,y2),表示框的左上角坐标和右下角坐标),一个置信度分数(Confidence Score),表示边界框中是否包含检测对象的概率和各个类别的概率(首先得到类别概率,经过Softmax可得到类别标签)。 1.1 Two stage方法 目前主流的基于深度学习的目标检测算法主要分为两类:Two stage和One stage。Two stage方法将目标检测过程分为两个阶段。第一个阶段是 Region Proposal 生成阶段,主要用于生成潜在的目标候选框(Bounding-box proposals)。这个阶段通常使用卷积神经网络(CNN)从输入图像中提取特征,然后通过一些技巧(如选择性搜索)来生成候选框。第二个阶段是分类和位置精修阶段,将第一个阶段生成的候选框输入到另一个 CNN 中进行分类,并根据分类结果对候选框的位置进行微调。Two stage 方法的优点是准确度较高,缺点是速度相对较慢。 常见Tow stage目标检测算法有:R-CNN系列、SPPNet等。 1.2 One stage方法 One stage方法直接利用模型提取特征值,并利用这些特征值进行目标的分类和定位,不需要生成Region Proposal。这种方法的优点是速度快,因为省略了Region Proposal生成的过程。One stage方法的缺点是准确度相对较低,因为它没有对潜在的目标进行预先筛选。 常见的One stage目标检测算法有:YOLO系列、SSD系列和RetinaNet等。 2 常见名词解释 2.1 NMS(Non-Maximum Suppression) 目标检测模型一般会给出目标的多个预测边界框,对成百上千的预测边界框都进行调整肯定是不可行的,需要对这些结果先进行一个大体的挑选。NMS称为非极大值抑制,作用是从众多预测边界框中挑选出最具代表性的结果,这样可以加快算法效率,其主要流程如下: 设定一个置信度分数阈值,将置信度分数小于阈值的直接过滤掉 将剩下框的置信度分数从大到小排序,选中值最大的框 遍历其余的框,如果和当前框的重叠面积(IOU)大于设定的阈值(一般为0.7),就将框删除(超过设定阈值,认为两个框的里面的物体属于同一个类别) 从未处理的框中继续选一个置信度分数最大的,重复上述过程,直至所有框处理完毕 2.2 IoU(Intersection over Union) 定义了两个边界框的重叠度,当预测边界框和真实边界框差异很小时,或重叠度很大时,表示模型产生的预测边界框很准确。边界框A、B的IOU计算公式为: 2.3 mAP(mean Average Precision) mAP即均值平均精度,是评估目标检测模型效果的最重要指标,这个值介于0到1之间,且越大越好。mAP是AP(Average Precision)的平均值,那么首先需要了解AP的概念。想要了解AP的概念,还要首先了解目标检测中Precision和Recall的概念。 首先我们设置置信度阈值(Confidence Threshold)和IoU阈值(一般设置为0.5,也会衡量0.75以及0.9的mAP值): 当一个预测边界框被认为是True Positive(TP)时,需要同时满足下面三个条件: Confidence Score > Confidence Threshold 预测类别匹配真实值(Ground truth)的类别 预测边界框的IoU大于设定的IoU阈值 不满足条件2或条件3,则认为是False Positive(FP)。当对应同一个真值有多个预测结果时,只有最高置信度分数的预测结果被认为是True Positive,其余被认为是False Positive。 Precision和Recall的概念如下图所示: Precision表示TP与预测边界框数量的比值 Recall表示TP与真实边界框数量的比值 改变不同的置信度阈值,可以获得多组Precision和Recall,Recall放X轴,Precision放Y轴,可以画出一个Precision-Recall曲线,简称P-R
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值