推送系统

说是推送系统有点大,其实就是一个消息广播功能吧。作用其实也就是由服务端接收到消息然后推送到订阅的客户端。

思路

对于推送最关键的是服务端向客户端发送数据,客户端向服务端订阅自己想要的消息。这样的好处就是有消息后才向客户端推送,相比于拉取数据不会产生许多无效的查询,实时性也高。

xmpp这种即时通信协议基于TCP长连接还是比较符合这种场景的。只需要在服务端增加一个模块用于接收用户订阅与数据的推送就完成了主体功能。

在xmpp协议里可以扩展组件,这样我们写一个组件,然后连接到xmpp服务器,这样就可以应用于不同的xmpp服务器。

准备工作

主要的环境

因为我比较熟悉openfire的体系,所以自然就用它。客户端暂时没有特别的需求,只是用于接收数据,所以用smack或者任何一款xmpp 客户端都可以。我为了简单就用smack写一个简单的代码。

需要用到的jar包

用到的了whack的core,在maven工程里直接引用即可,相关的依赖包会自动加载进来

<dependency>
<groupId>org.igniterealtime.whack</groupId>
<artifactId>core</artifactId>
<version>2.0.1-SNAPSHOT</version>
<type>jar</type>
</dependency>

核心模块

推送服务

推送服务就是等待或者获得需要推送的消息数据后向用户广播出去的服务。因为这里暂时没有设定数据的场景,所以就简单的用一个阻塞队列来表示。步骤:

  1. 数据通过推送接口写入到推送服务
  2. 推送服务将数据写入到消息队列
  3. 发送线程检测到消息后取出并发给订阅的客户端

在此我写了一个PushServer的类用于表示推送服务,这个类里包含了:

  1. 一个消息队列
  2. 一个发送线程
  3. 一个订阅列表
  4. 以及一些发送相关的xmpp组件

消息队列

//消息列表
private BlockingQueue<Packet> packetQueue;

使用到了生产者消费者模式,所以用了一个阻塞队列,用于存放等待发送的消息数据。

发送线程

private class PacketSenderThread extends Thread {
private volatile Boolean shutdown = false;
private BlockingQueue<Packet> queue;
private Component component;
private ComponentManager componentManager; public PacketSenderThread(ComponentManager componentManager, Component component, BlockingQueue<Packet> queue) {
this.componentManager = componentManager;
this.component = component;
this.queue = queue;
} public void run() {
while (!shutdown) {
Packet p;
try {
p = queue.take();
componentManager.sendPacket(component, p);
} catch (InterruptedException e1) {
System.err.println(e1.getStackTrace());
} catch (ComponentException e) {
e.printStackTrace();
}
}
} public void shutdown() {
shutdown = true;
this.interrupt();
} }

这个线程继承了Thread,线程的功能很简单,就是一直从queue中获得消息,因为是阻塞的队列,所以没有消息时会阻塞,一旦有消息就会执行发送sendPacket将包发送出去。

这里使用到了componentManager,这个是openfire实现的一个组件管理类,通过这个类的对象可以发送xmpp数据包。

增加shutdown方法,使得线程可以在外部进行退出操作。

订阅列表

//订阅列表
private Set<JID> subscriptions; public synchronized void subscription(JID jid) {
subscriptions.add(jid);
} public synchronized void unsubscription(JID jid) {
subscriptions.remove(jid);
}

只有订阅了这个推送服务的客户端才会进行推送操作,这里的代码就是用于订阅与退订操作。用了一个HashSet来存储。

xmpp组件

public class PushComponent extends AbstractComponent{

	public PushComponent() {
} @Override
public String getDescription() {
return "用于消息推送服务组件,主要功能就是将消息转发给具体的客户端,实现消息中转的功能";
} @Override
public String getName() {
return "pusher";
} @Override
protected void handleMessage(Message message) {
} } public class PushManager {
private static PushManager _instance = new PushManager();
private Map<String, PushServer> pushServers;
private ExternalComponentManager manager; private PushManager() {
pushServers = new ConcurrentHashMap<String, PushServer>();
manager = new ExternalComponentManager("192.168.149.214", 5275);
manager.setSecretKey("push", "test");
manager.setMultipleAllowed("push", true);
} public static PushManager getInstance() {
return _instance;
} public void init() {
try {
//初始化PushServer
PushServer pushSvr = new PushServer("push", manager);
pushServers.put("push", pushSvr);
//注册Component到xmpp服务器
manager.addComponent(pushSvr.getPushDomain(), pushSvr.getComp());
} catch (ComponentException e) {
e.printStackTrace();
}
} public PushServer getPushServer(String pushDomain) {
return pushServers.get(pushDomain);
}
}

这里的PushComponent就是一个xmpp组件,相当于一个扩展模块,可以接收消息并处理消息,也就是自己写一些和xmpp相关的业务功能。

PushManager就是管理组件并连接到xmpp服务器的一个类。

服务端启动

public class App
{
public static void main( String[] args )
{
PushManager.getInstance().init();
//推送消息
PushServer ps = PushManager.getInstance().getPushServer("push");
ps.start(); JID client1 = new JID("1twja8e8yr@domain/1twja8e8yr");
ps.subscription(client1);
try {
for (Integer i = 0; i< 200; i++) {
ps.putPacket("推送消息200:" + i.toString());
Thread.sleep(1);
}
Thread.sleep(5000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
ps.stop();
System.out.println("go die");
}
}

这段代码模拟了服务的启动,同时为了简化功能这里直接添加了一个订阅用户。

客户端

public class TestAnonymous {
public static void main(String[] args) {
AbstractXMPPConnection connection = SesseionHelper.newConn("192.168.149.214", 5223, "domain");
try {
connection.login();//匿名登录 connection.addAsyncStanzaListener(new StanzaListener() { @Override
public void processPacket(Stanza packet) throws NotConnectedException {
System.out.println((new Date()).toString()+ ":" + packet.toXML());
}
}, new StanzaFilter() {
@Override
public boolean accept(Stanza stanza) {
return stanza instanceof Message;
}
});
} catch (XMPPException | SmackException | IOException e) {
e.printStackTrace();
} while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

客户端代码启动一个xmpp连接,然后登录到服务器,同时订阅消息,将收到的消息print出来。

整个过程就完成了。

注:此文章为原创,欢迎转载,请在文章页面明显位置给出此文链接!
若您觉得这篇文章还不错请点击下右下角的推荐,非常感谢!

在Openfire上弄一个简单的推送系统的更多相关文章

  1. 用C写一个简单的推箱子游戏(二)

    下面接着上一篇随笔<用C写一个简单的推箱子游戏(一)>来写 tuidong()函数是用来判断游戏人物前方情况的函数,是推箱子游戏中非常重要的一个函数,下面从它开始继续介绍推箱子的小程序怎么 ...

  2. 用C写一个简单的推箱子游戏(一)

    我现在在读大二,我们有一门课程叫<操作系统>,课程考查要求我们可以写一段程序或者写Windows.iOS.Mac的发展历程.后面我结合网上的资料参考,就想用自己之前简单学过的C写一关的推箱 ...

  3. 使用SignalR ASP.NET Core来简单实现一个后台实时推送数据给Echarts展示图表的功能

    什么是 SignalR ASP.NET Core ASP.NET Core SignalR 是一种开放源代码库,可简化将实时 web 功能添加到应用程序的功能. 实时 web 功能使服务器端代码可以立 ...

  4. 用Pomelo 搭建一个简易的推送平台

    前言 实际上,个人感觉,pomelo 目前提供的两个默认sioconnector和hybridconnector 使用的协议并不适合用于做手机推送平台,在pomelo的一份公开ppt里面,有提到过, ...

  5. Android高效率编码-第三方SDK详解系列(二)——Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能

    Android高效率编码-第三方SDK详解系列(二)--Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能 我的本意是第二篇写Mob的shareSD ...

  6. 【译】建立属于你的个人高效系统——效率专家 Mike Vardy 教你如何设置一个简单的个人高效系统

    原文:http://mux.baidu.com/?p=5300 百度MUX 已经有太多的高效系统供人使用,而对于那些刚刚开始,想寻求更好方法完成他们任务,项目,目标的人来说,要做一个高效系统却是相当艰 ...

  7. 最简单的推送--uexGetui

    个推插件使用指南 配置方法这里不再复述,详情请参见插件接入指引 怎样创建一个最简单的推送? //只需要两个方法 uexGetui.initialize(data); uexGetui.onInitia ...

  8. 基于page的简单页面推送技术

    我们可以先看下简单效果,打开2个页面可以看到推送效果 服务端我们只需要下面一个方法 using System; using System.Collections.Generic; using Syst ...

  9. MPush开源消息推送系统:简洁、安全、支持集群

    引言由于之前自己团队需要一个消息推送系统来替换JPUSH,一直找了很久基本没有真正可用的开源系统所有就直接造了个轮子,造轮子的时候就奔着开源做打算的,只是后来创业项目失败一直没时间整理这一套代码,最近 ...

随机推荐

  1. bootstrap + requireJS+ director+ knockout + web API = 一个时髦的单页程序

    也许单页程序(Single Page Application)并不是什么时髦的玩意,像Gmail在很早之前就已经在使用这种模式.通常的说法是它通过避免页面刷新大大提高了网站的响应性,像操作桌面应用程序 ...

  2. 使用UIBezierPath绘制图形

    当需要画图时我们一般创建一个UIView子类, 重写其中的drawRect方法 再drawRect方法中利用UIBezierPath添加画图 UIBezierPath的使用方法: (1)创建一个Bez ...

  3. 基于netty http协议栈的轻量级流程控制组件的实现

    今儿个是冬至,所谓“冬大过年”,公司也应景五点钟就放大伙儿回家吃饺子喝羊肉汤了,而我本着极高的职业素养依然坚持留在公司(实则因为没饺子吃没羊肉汤喝,只能呆公司吃食堂……).趁着这一个多小时的时间,想跟 ...

  4. [干货来袭]C#6.0新特性

    微软昨天发布了新的VS 2015 ..随之而来的还有很多很多东西... .NET新版本 ASP.NET新版本...等等..太多..实在没消化.. 分享一下也是昨天发布的新的C#6.0的部分新特性吧.. ...

  5. .NET应用和AEAI CAS集成详解

    1 概述 数通畅联某综合SOA集成项目的统一身份认证工作,需要第三方系统配合进行单点登录的配置改造,在项目中有需要进行单点登录配置的.NET应用系统,本文专门记录.NET应用和AEAI CAS的集成过 ...

  6. C#发送邮箱

    之前自己从来没有做过发送邮箱的功能,前段时间项目需要,在找了很多帖子之后,终于实现了. 之后有整理了一下,写了一个类.直接给类传递信息,就可以发送了. 这里还需要说明的是,发送邮箱需要开通POP3/S ...

  7. springmvc的拦截器

    什么是拦截器                                                         java里的拦截器是动态拦截action调用的对象.它提供了一种机制可以使 ...

  8. 设计模式之单例模式(Singleton)

    设计模式之单例模式(Singleton) 设计模式是前辈的一些经验总结之后的精髓,学习设计模式可以针对不同的问题给出更加优雅的解答 单例模式可分为俩种:懒汉模式和饿汉模式.俩种模式分别有不同的优势和缺 ...

  9. T-SQL学习记录

    T-sql是对SQL(structure query language )的升级.可以加函数. 系统数据库:master管理数据库.model模版数据库,msdb备份等操作需要用到的数据库,tempd ...

  10. Win10连接远程桌面时提示“您的凭据不工作”

    我遇到这个问题的时候查找网上都给出一堆高大上的解决办法, 然而我的错误实际上是用户名的问题, 很多人以为远程用户名就一定是锁屏状态下的登录名, 其实不是,跟自己设置有关,所以首先应该检查远程用户名是否 ...