在 Connection 抽象类中,有一个属性 collectors ,类型是 Collection<PacketCollector> 。 collectors 是一个由 PacketCollector组成的集合。
一、简介
PacketCollector 是一个Packet数据搜集器,根据设置的filter来接收packet数据。
如果filter为空,则接收全部的packet数据。
二、工作原理
怎么接收呢?
PacketCollector中有一个 ArrayBlockingQueue 类型的结果队列 resultQueue,
所有的满足条件的packet都进入队列。
进队列的规则是:从队列尾部进,从队列头部出。队列满了,先进的 packet 就从队列头部溢出,让后来的 packet 进入队列。
这个规则就是有 processPacket(Packet packet) 来执行的,此方法接收新的 packet,然后执行上述进队列的规则。
三、用途
那么,这个 PacketCollector 有什么用呢?
他是为了专门满足某些条件的 packet,比如:在一个修改密码的操作之后,加上一个packetColletor 专门搜集能够响应这个操作的返回结果。
如果这个 packetCollector 里面的 packet 一个也没有,也就是队列为空,则没有收到服务器端的响应。
如果有packet ,就可以获得这个packet 读取返回的结果。
四、用法举例
1、创建一个filter
PacketFilter filter = new AndFilter(new PacketIDFilter(reg.getPacketID()),
new PacketTypeFilter(IQ.class));
满足这个filter的所有 packet 都会进入 packetCollector 的队列中。2、用这个filter 创建一个 packetCollector
PacketCollector collector = connection.createPacketCollector(filter);
3、发送数据到服务器端
connection.sendPacket(reg);
4、接收响应
IQ result = (IQ)collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
5、结束搜集
collector.cancel();
五、队列的创建和操作
1、根据filter 创建一个 PacketCollector 并加入集合中
protected final Collection<PacketCollector> collectors = new ConcurrentLinkedQueue<PacketCollector>();
public PacketCollector createPacketCollector(PacketFilter packetFilter) {
PacketCollector collector = new PacketCollector(this, packetFilter);
collectors.add(collector);
return collector;
}
所以,每个connect 可以增加任意多个 packetCollector 。
在什么时候加,在调用 connect.setPacket(packet)之前加,参见用法举例的步骤。
2、获取队列中的数据
collector.nextResult()获取结果,这个方法会等待队列,直到返回结果为止。得到的结果会弹出队列,下一个结果成为队列的顶端元素。
还有一个方法:
collector.pollResult() 也是获取结果,如果有就返回结果,没有就返回null,不会锁定队列。
3、结束搜集
collector.cancel()
六、搜集工作的入口
之前在 PacketReader里面,触发Listener 前面。
private void processPacket(Packet packet) { if (packet == null) { return; } // Loop through all collectors and notify the appropriate ones. for (PacketCollector collector : connection.getPacketCollectors()) { collector.processPacket(packet); } // Deliver the incoming packet to listeners. listenerExecutor.submit(new ListenerNotification(packet)); }
七、补充
PacketCollector中队列的大小在配置文件中设置。
配置文件 META-INF/smack-config.xml
对应的设置 <packetCollectorSize>10000</packetCollectorSize>
默认的是 10000