android环境下的即时通讯,android即时通讯
首先了解一下即时通信的概念。通过消息通道 传输消息对象,一个账号发往另外一账号,只要账号在线,可以即时获取到消息,这就是最简单的即使通讯。消息通道可由TCP/IP UDP实现。通俗讲就是把一个人要发送给另外一个人的消息对象(文字,音视频,文件)通过消息通道(C/S实时通信)进行传输的服务。即时通讯应该包括四种形式,在线直传、在线代理、离线代理、离线扩展。在线直传指不经过服务器,直接实现点对点传输。在线代理指消息经过服务器,在服务器实现中转,最后到达目标账号。离线代理指消息经过服务器中转到达目标账号,对方不在线时消息暂存服务器的数据库,在其上线再传发。离线扩展指将暂存消息以其它形式,例如邮件、短信等转发给目标账号。
此外,我们还需要认识一下计算机网络相关的概念。经典的计算机网络四层模型中,TCP和UDP是传输层协议,包含着消息通信内容。ip为网络层协议,是一种网络地址。TCP/IP,即传输控制协议/网间协议,定义了主机如何连入因特网及数据如何在它们之间传输的标准。Socket,又称“套接字”, 在应用层和传输层之间的一个抽象层,用于描述 IP 地址和端口,是一个通信连的句柄,应用程序通常通过“套接字”向网络发送请求或者应答网络请求,它就是网络通信过程中端点的抽象表示。它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。XMPP(可扩展消息处理现场协议)是基于可扩展标记语言(XML)的协议,应用于即时通讯场景的应用层协议,底层通过Socket实现。它用于即时消息(IM)以及在线现场探测。它在促进服务器之间的准即时操作。这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息, 即使其操作系统和浏览器不同。这样实现即时通讯就有两种方案,一是从套接字入手,直接利用socket提供的接口进行数据的传送。二是借助开源工具(服务器openfire),用XMPPConnection创建连接。
XMPP是实现即时通讯使用较为普遍的做法。XMPP中,各项工作都是通过在一个 XMPP 流上发送和接收 XMPP 节来完成的。核心 XMPP 工具集由三种基本节组成,这三种节分别为<presence>、出席<message>、<iq>。XMPP 流由两份 XML 文档组成,通信的每个方向均有一份文档。这份文档有一个根元素<stream:stream>,这个根元素的子元素由可路由的节以及与流相关的顶级子元素构成。xmpp协议同样包括客户端和服务器。客户端基于 Android 平台进行开发。负责初始化通信过程,进行即时通信时,由客户端负责向服务器发起创建连接请求。系统通过 GPRS 无线网络与Internet 网络建立连接,通过服务器实现与 Android 客户端的即时通信脚。服务器端则采用 Openfire 作为服务器。 允许多个客户端同时登录并且并发的连接到一个服务器上。服务器对每个客户端的连接进行认证,对认证通过的客户端创建会话,客户端与服务器端之间的通信就在该会话的上下文中进行。使用了 asmark 开源框架实现的即时通讯功能.该框架基于开源的 XMPP 即时通信协议,采用 C/S 体系结构,通过 GPRS 无线网络用TCP 协议连接到服务器,以架设开源的 Openfn'e 服务器作为即时通讯平台。xmpp消息通道的创建:
先配置通道信息进行连接
ConnectionConfiguration configuration = new ConnectionConfiguration(HOST, PORT),
设置Debug信息和安全模式
configuration.setDebuggerEnabled(true);
configuration.setSecurityMode(SecurityMode.disabled),
最后才是建立连接
conn.connect();
在ContentObserver的实现类中观察消息变化。XMPPConnection.getRoster()获取联系人列表对象。用xmpp协议编写通讯协议的大致思路可以如下。进入登陆界面,通过xmppconnection的login方法实现登陆,登陆成功进入主界面。主界面包含两个Fragment,分别用来显示联系人和聊天记录。创建联系人和短信的数据观察者,在联系人、短信服务中分别设定监听RosterListener()、ChatManagerListener(),接受联系人和短信信息,同时将相关信息添加到内容提供者中。在内容提供者中设定一个内容观察者,当数据发生变化时通知界面更新。
本文的重点是利用Socket的接口实现即时通讯,因为绝大多数即时通讯的底层都是通过Socket实现的。其基本的业务逻辑可描述如下。用户进入登陆界面后,提交账号密码 经服务端确定,返回相关参数用于确定连接成功。进入聊天界面或好友界面。点击联系人或聊天记录的条目,进入聊天界面。当移动端再次向服务器发送消息时,由服务器转发消息内容给目标账号。同时更新界面显示。这样就完成即时通讯的基本功能。当然,也可以添加一个后台服务,当用户推出程序时,在后台接受消息。不难看出,对于即时通讯来讲,有三个关注点:消息通道、消息内容、消息对象。因此,主要逻辑也是围绕这三个点展开。消息通道实现传输消息对象的发送和接收。为Socket(String host, int port)传入服务其地址和端口号,即可创建连接。消息内容的格式应该与服务器保持一致。接受数据时,获取输入流并用DataInputStream包装,通过输入流读取server发来的数据。发送数据时,获取输出流并用DataOutputStream包装,通过输出流往server发送数据。消息内容中应该包括发送者、接受者信息、数据类型等。消息对象就是消息的发送者和消息的接受者。接下来在代码中进行详细的讲解。
创建一个消息的基类,实现xml文件和字符串的转换,用到Xsream第三方jar包。这样当创建消息类时,继承该方法,就可以直接在类中实现数据的转换。
/** * Created by huang on 2016/12/3. */ public class ProtacolObjc implements Serializable { public String toXml() { XStream stream = new XStream(); //将根节点转换为类名 stream.alias(this.getClass().getSimpleName(), this.getClass()); return stream.toXML(this); } public Object fromXml(String xml) { XStream x = new XStream(); x.alias(this.getClass().getSimpleName(), this.getClass()); return x.fromXML(xml); } //创建Gson数据和字符串之间转换的方法,适应多种数据 public String toGson() { Gson gson = new Gson(); return toGson(); } public Object fromGson(String result) { Gson gson = new Gson(); return gson.fromJson(result, this.getClass()); } }
创建线程工具,指定方法运行在子线程和主线程中。由于网络操作需要在子线程中,界面更新需要在主线程中,创建线程工具可以方便选择线程。
import android.os.Handler; /** * Created by huang on 2016/12/5. */ public class ThreadUtils { private static Handler handler = new Handler(); public static void runUIThread(Runnable r){ handler.post(r); } public static void runINThread(Runnable r){ new Thread(r).start(); } }
创建消息的工具类,包括消息内容、消息类型、消息本省等。由于服务器返回的内容中包含消息的包名信息所以消息本身的包名应该于服务其保持一直。
/** * Created by huang on 2016/12/3. * 消息内容 */ public class QQMessage extends ProtacolObjc { public String type = QQmessageType.MSG_TYPE_CHAT_P2P;// 类型的数据 chat login public long from = 0;// 发送者 account