`
pjwqq
  • 浏览: 81341 次
社区版块
存档分类
最新评论

AndroidPN客户端的阻塞读写(2)

阅读更多

      AndroidPN客户端分别启动了读和写线程之后,如果有某种写必须等待结果的又如何处理呢?比如客户端向服务端发个消息,要求等待服务端返回后再对本地逻辑做处理。想象一下客户端要求修改密码,PacketWriter把请求write出去后,成功或失败信息肯定是从PacketReader线程中获得,那么如何把二者关联起来呢,看看asmack的做法。

     PacketCollector类

public class PacketCollector {

    private PacketFilter packetFilter;
    private ArrayBlockingQueue<Packet> resultQueue;
    private Connection connection;
    private boolean cancelled = false;

    /**
     * Creates a new packet collector. If the packet filter is <tt>null</tt>, then
     * all packets will match this collector.
     *
     * @param conection the connection the collector is tied to.
     * @param packetFilter determines which packets will be returned by this collector.
     */
    protected PacketCollector(Connection conection, PacketFilter packetFilter) {
    	this(conection, packetFilter, SmackConfiguration.getPacketCollectorSize());
    }

    /**
     * Creates a new packet collector. If the packet filter is <tt>null</tt>, then
     * all packets will match this collector.
     *
     * @param conection the connection the collector is tied to.
     * @param packetFilter determines which packets will be returned by this collector.
     * @param maxSize the maximum number of packets that will be stored in the collector.
     */
    protected PacketCollector(Connection conection, PacketFilter packetFilter, int maxSize) {
        this.connection = conection;
        this.packetFilter = packetFilter;
        this.resultQueue = new ArrayBlockingQueue<Packet>(maxSize);
    }

    /**
     * Explicitly cancels the packet collector so that no more results are
     * queued up. Once a packet collector has been cancelled, it cannot be
     * re-enabled. Instead, a new packet collector must be created.
     */
    public void cancel() {
        // If the packet collector has already been cancelled, do nothing.
        if (!cancelled) {
            cancelled = true;
            connection.removePacketCollector(this);
        }
    }

    /**
     * Returns the packet filter associated with this packet collector. The packet
     * filter is used to determine what packets are queued as results.
     *
     * @return the packet filter.
     */
    public PacketFilter getPacketFilter() {
        return packetFilter;
    }

    /**
     * Polls to see if a packet is currently available and returns it, or
     * immediately returns <tt>null</tt> if no packets are currently in the
     * result queue.
     *
     * @return the next packet result, or <tt>null</tt> if there are no more
     *      results.
     */
    public Packet pollResult() {
    	return resultQueue.poll();
    }

    /**
     * Returns the next available packet. The method call will block (not return)
     * until a packet is available.
     *
     * @return the next available packet.
     */
    public Packet nextResult() {
        try {
			return resultQueue.take();
		}
		catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
    }

    /**
     * Returns the next available packet. The method call will block (not return)
     * until a packet is available or the <tt>timeout</tt> has elapased. If the
     * timeout elapses without a result, <tt>null</tt> will be returned.
     *
     * @param timeout the amount of time to wait for the next packet (in milleseconds).
     * @return the next available packet.
     */
    public Packet nextResult(long timeout) {
    	try {
			return resultQueue.poll(timeout, TimeUnit.MILLISECONDS);
		}
		catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
    }

    /**
     * Processes a packet to see if it meets the criteria for this packet collector.
     * If so, the packet is added to the result queue.
     *
     * @param packet the packet to process.
     */
    protected void processPacket(Packet packet) {
        if (packet == null) {
            return;
        }
        
        if (packetFilter == null || packetFilter.accept(packet)) {
        	while (!resultQueue.offer(packet)) {
        		// Since we know the queue is full, this poll should never actually block.
        		resultQueue.poll();
        	}
        }
    }
}

 这个类相当赞,最喜欢这种简单的东西了,我觉得我可以照抄呵呵,基本上不需要看其它代码就能猜asmack是怎么干的了,看看流程

 

 

1.首先,如果有需要,比如要修改密码了,就将PacketCollect注册到connection上

   /**
     * Creates a new packet collector for this connection. A packet filter determines
     * which packets will be accumulated by the collector. A PacketCollector is
     * more suitable to use than a {@link PacketListener} when you need to wait for
     * a specific result.
     * 
     * @param packetFilter the packet filter to use.
     * @return a new packet collector.
     */
    public PacketCollector createPacketCollector(PacketFilter packetFilter) {
        PacketCollector collector = new PacketCollector(this, packetFilter);
        // Add the collector to the list of active collectors.
        collectors.add(collector);
        return collector;
    }

 PacketFilter是个过滤器,对于修改密码而言,我只对服务端返回的密码修改结果感兴趣,其它无视,那么它只将相关的接收到的packet放进PacketCollector的ArrayBlockingQueue<Packet>中。注意下processPacket这个方法,队列满了就开始丢弃之前的packet.

 

 

2.发起修改密码请求到服务端,其实就是通过PacketWriter线程write一个packet给服务器。

 

3.坐等服务端返回,可用nextResult()方法,是一直阻塞,还是阻塞一定时间,你自己来定,一般应该是阻塞几秒就差不多了。

 

4.最后无论有没服务端回应,cancel掉这个PacketCollector,即从connection中将之删除。

 

来看一段AccounterManager中源码:

    public void createAccount(String username, String password, Map<String, String> attributes)
            throws XMPPException
    {
        if (!supportsAccountCreation()) {
            throw new XMPPException("Server does not support account creation.");
        }
        Registration reg = new Registration();
        reg.setType(IQ.Type.SET);
        reg.setTo(connection.getServiceName());
        attributes.put("username",username);
        attributes.put("password",password);
        reg.setAttributes(attributes);
        PacketFilter filter = new AndFilter(new PacketIDFilter(reg.getPacketID()),
                new PacketTypeFilter(IQ.class));
        PacketCollector collector = connection.createPacketCollector(filter);
        connection.sendPacket(reg);
        IQ result = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
        // Stop queuing results
        collector.cancel();
        if (result == null) {
            throw new XMPPException("No response from server.");
        }
        else if (result.getType() == IQ.Type.ERROR) {
            throw new XMPPException(result.getError());
        }
    }

 这个过程还是相当清楚的。

总结下,asmack写线程和读线程之间,通过分发指定消息类型到指定的同步队列,利用同步队列的阻塞,来实现发出消息和收到消息的关联。

 

1
2
分享到:
评论

相关推荐

    androidpn 客户端模拟代码

    2. **心跳机制**:为了保持连接状态并检测网络中断,客户端会定期发送心跳包给服务端。这有助于确认客户端在线并准备接收消息。 3. **消息处理**:客户端需要实现接收和解析服务端发送过来的JSON格式的推送消息。...

    androidpn客户端代码

    2. **客户端组件**: - **Service**:AndroidPN客户端通常包含一个后台Service,持续运行并监听服务器的推送消息。 - **BroadcastReceiver**:用于接收系统级别的广播,当设备接收到新的推送消息时触发。 - **...

    AndroidPn客户端和服务端

    Androidpn客户端 和服务端源码下载,实现了消息推送。具体使用方法可百度。

    androidpn 客户端和服务端

    "AndroidPN 客户端和服务端"是一个完整的推送通知服务解决方案,主要针对Android平台。这个项目包括了客户端应用程序和服务器端的实现,旨在提供实时、可靠的信息推送功能,使得应用程序能够在用户不主动打开应用的...

    androidpn客户端与服务端

    接下来是客户端部分,`androidpn-client-0.5.0`包含了客户端的源代码。客户端的职责包括: 1. **注册**:客户端在启动时会连接到服务端,并注册其设备以便接收通知。这通常涉及到获取GCM或FCM的注册ID并将其发送到...

    AndroidPn(客户端和服务端)

    2. **AndroidPn客户端**:客户端是运行在Android设备上的应用程序,它的功能包括: - **连接建立**:通过TCP/IP或WebSocket等协议与服务端建立安全的连接。 - **身份认证**:向服务端提供身份凭证,以证明客户端...

    androidpn客户端和服务端

    "AndroidPN"是一个基于Android平台的推送通知服务(Push Notification)客户端和服务端的实现。它允许应用程序在后台运行,即使用户没有直接与应用交互,也能接收到服务器发送的消息。这个技术对于开发实时通信或者...

    著名的AndroidPN消息推送客户端

    AndroidPN(Android Push Notification)是一种基于XMPP(Extensible Messaging and Presence Protocol)协议的开源消息推送客户端,主要用于Android平台。XMPP是一种开放标准的即时通讯协议,它允许应用程序通过...

    androidpn-client推送客户端

    AndroidPN(Android Push Notification)客户端是一款专门为Android操作系统设计的应用程序,用于实现远程服务器向设备推送通知的功能。在移动应用开发中,推送通知是一项至关重要的特性,它允许应用程序在后台状态...

    androidpn-client

    2. 可扩展性:基于XMPP协议,AndroidPN客户端支持自定义扩展,可以适应各种复杂的应用场景。 3. 安全性:客户端和服务器之间的通信进行了加密,保证了数据的安全传输。 4. 稳定性:针对Android系统的特点进行优化,...

    基于androidpn设计的android客户端远程推送demo

    这个"基于androidpn设计的android客户端远程推送demo"应该包含以下部分: 1. **源代码**:Android应用的源代码,可能包括Activity、BroadcastReceiver、Service等关键组件。 2. **配置文件**:如GoogleService....

    androidpn(客户端和服务器端)

    androidpn 的客户端和服务器端源码. 使用说明: 解压后得到两个压缩包: androidpn-client.zip和androidpn-server-0.5.0-bin.zip, 解压两个包,Eclipse导入client,配置好目标平台,打开raw/androidpn.properties...

    基于Android TV BOX上AndroidPN客户端, .zip

    Android是一种基于Linux内核(不包含GNU组件)的自由及开放源代码的移动操作系统,主要应用于移动设备,如智能手机和平板电脑。该系统最初由安迪·鲁宾开发,后被Google公司收购并注资,随后与多家硬件制造商、软件...

    androidpn-client-0.5.0

    《AndroidPN客户端0.5.0:XMPP技术在手机消息推送中的应用》 AndroidPN客户端0.5.0是一款专为Android平台设计的消息推送服务,它基于XMPP(Extensible Messaging and Presence Protocol)协议,提供了开源的客户端...

    androidpn-client-0.5.0.zip

    "AndroidPN-client-0.5.0.zip" 是一个针对Android平台的Push Notification服务客户端的压缩包文件。Push Notification(简称PN)是一种允许服务器向移动设备推送消息的技术,无需应用程序处于活动状态。在这个版本...

    androidpn 消息推送客户端+服务器端

    AndroidPN客户端是安装在用户Android设备上的应用程序,它的主要任务是接收来自服务器端的消息并将其展示给用户。客户端通过注册一个唯一的设备ID到服务器,然后保持与服务器的持久连接,以便随时接收推送通知。这种...

    androidpn服务端,客户端.rar

    本资源包提供了AndroidPN服务端和客户端的源码,以及相关的部署说明,便于开发者快速理解和实现推送通知功能。 一、AndroidPN服务端 AndroidPN服务端是基于Java语言开发的,它使用了Spring框架和Hibernate ORM来...

    androidpn基于Xmpp的消息推送源码.zip

    androidpn基于Xmpp的消息推送源码包含了完整的客户端和服务器端。androidpn客户端需要用到一个基于java的开源XMPP协议包asmack,这个包同样也是基于openfire下的另外一个开源项目smack,不过我们不需要自己编译,...

    androidpn-client 0.5 推送

    2. **客户端**:AndroidPN客户端是安装在Android设备上的应用程序,它负责注册到服务端,接收并处理来自服务端的推送消息。这里的"androidpn-client 0.5.01111"就是客户端的源码包,包含了实现消息推送所需的所有...

Global site tag (gtag.js) - Google Analytics