xmpp协议的使用.doc_第1页
xmpp协议的使用.doc_第2页
xmpp协议的使用.doc_第3页
xmpp协议的使用.doc_第4页
xmpp协议的使用.doc_第5页
已阅读5页,还剩41页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

在android里面用的smack包其实叫做asmack,该包提供了两种不同的连接方式:socket和httpclient。该并且提供了很多操作xmpp协议的API,也方便各种不同自定义协议的扩展。我们不需要自己重新去定义一套接收机制来扩展新的协议,只需继承然后在类里处理自己的协议就可以了。而本文今天主要说两点,一点就是消息是如何接收的,另一点就是消息是如何通知事件的。 总的思路1.使用socket连接服务器2.将XmlPullParser的数据源关联到socket的InputStream3.启动线程不断循环处理消息4.将接收到的消息解析xml处理封装好成一个Packet包5.将包广播给所有注册事件监听的类 逐步击破(声明在看下面的文章时,最好先理解一下smack的使用,这样才能达到深入的理解)(谨记:上图只显示本文章解释所要用到的类和方法,减缩了一些跟本文主题无关的代码,只留一条贯穿着从建立连接到接收消息的线。)解析这块东西打算从最初的调用开始作为入口,抽丝剥茧,逐步揭开。1.PacketListener packetListener = new PacketListener() Override public void processPacket(Packet packet) System.out .println(Activity-processPacket+ packet.toXML(); ; PacketFilter packetFilter = new PacketFilter() Override public booleanaccept(Packet packet) System.out.println(Activity-accept+ packet.toXML(); return true; ; 解释:创建包的监听以及包的过滤,当有消息到时就会广播到所有注册的监听,当然前提是要通过packetFilter的过滤。2.connection = new XMPPConnection();XMPPConnection在这构造函数里面主要配置ip地址和端口(super(new ConnectionConfiguration(09, 9991);)3.connection.addPacketListener(packetListener, packetFilter);connection.connect();注册监听,开始初始化连接。4.public voidconnect() / Stablishes the connection, readers and writers connectUsingConfiguration(config);5.private void connectUsingConfiguration(ConnectionConfiguration config) String host = config.getHost(); intport = config.getPort(); try this.socket= newSocket(host, port); catch(UnknownHostException e) e.printStackTrace(); catch(IOException e) e.printStackTrace(); initConnection(); 通过之前设置的ip和端口,建立socket对象6.protected void initDebugger() Class debuggerClass = null; try debuggerClass = Class.forName(com.simualteSmack.ConsoleDebugger); Constructor constructor = debuggerClass.getConstructor( Connection.class, Writer.class, Reader.class); debugger= (SmackDebugger) constructor.newInstance(this, writer, reader); reader= debugger.getReader(); catch(ClassNotFoundException e1) /TODOAuto-generated catch block e1.printStackTrace(); catch(Exception e) throw newIllegalArgumentException( Cant initialize the configured debugger!, e); private void initReaderAndWriter() try reader = newBufferedReader(newInputStreamReader(socket .getInputStream(), UTF-8); catch(UnsupportedEncodingException e) /TODOAuto-generated catch block e.printStackTrace(); catch(IOException e) /TODOAuto-generated catch block e.printStackTrace(); initDebugger();private void initConnection() / Set the reader and writer instance variables initReaderAndWriter(); packetReader = new PacketReader(this); addPacketListener(debugger.getReaderListener(), null); / Start the packet reader. The startup() method will block until we / get an opening stream packet back from server. packetReader.startup();从三个方法可以看出,建立reader和writer的对象关联到socket的InputStream,实例化ConsoleDebugger,该类主要是打印出接收到的消息,给reader设置了一个消息的监听。接着建立PacketReader对象,并启动。PacketReader主要负责消息的处理和通知7.public class PacketReader Private ExecutorService listenerExecutor; private boolean done; Private XMPPConnection connection; Private XmlPullParser parser; Private Thread readerThread; Protected PacketReader(finalXMPPConnection connection) this.connection= connection; this.init(); /* * Initializes the reader in order to be used. The reader is initialized * during the first connection and when reconnecting due to an abruptly * disconnection. */ protected void init() done= false; readerThread= newThread() public voidrun() parsePackets(this); ; readerThread.setName(Smack Packet Reader ); readerThread.setDaemon(true); / create an executor to deliver incoming packets to listeners. / we will use a single thread with an unbounded queue. listenerExecutor= Executors .newSingleThreadExecutor(newThreadFactory() Override publicThread newThread(Runnable r) Thread thread = newThread(r, smack listener processor); thread.setDaemon(true); returnthread; ); resetParser(); /* * Starts the packet reader thread and returns once a connection to the * server has been established. A connection will be attempted for a maximum * of five seconds. An XMPPException will be thrown if the connection fails. * */ public voidstartup() readerThread.start(); /* * Shuts the packet reader down. */ public voidshutdown() done= true; / Shut down the listener executor. listenerExecutor.shutdown(); private voidresetParser() try parser= XmlPullParserFactory.newInstance().newPullParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); parser.setInput(connection.reader); catch(XmlPullParserException xppe) xppe.printStackTrace(); /* * Parse top-level packets in order to process them further. * *paramthread * the thread that is being used by the reader to parse incoming * packets. */ private void parsePackets(Thread thread) try Int eventType = parser.getEventType(); do if(eventType = XmlPullParser.START_TAG) if(parser.getName().equals(message) processPacket(PacketParserUtils.parseMessage(parser); System.out.println(START_TAG); else if(eventType = XmlPullParser.END_TAG) System.out.println(END_TAG); eventType = parser.next(); while(!done& eventType != XmlPullParser.END_DOCUMENT & thread = readerThread); catch(Exception e) e.printStackTrace(); if(!done) private void processPacket(Packet packet) if(packet = null) return; / Loop through all collectors and notify the appropriate ones. for(PacketCollector collector : connection.getPacketCollectors() cessPacket(packet); / Deliver the incoming packet to listeners. listenerExecutor.submit(newListenerNotification(packet); /* * A runnable to notify all listeners of a packet. */ private class ListenerNotification implements Runnable Private Packet packet; Public ListenerNotification(Packet packet) this.packet= packet; public void run() for(ListenerWrapper listenerWrapper : connection.recvListeners .values() listenerWrapper.notifyListener(packet); 创建该类时就初始化线程和ExecutorService ,接着调用resetParser() 方法为parser设置输入源(这里是重点,parser的数据都是通过这里获取),调用startup启动线程,循环监听parser,如果接收到消息根据消息协议的不同将调用PacketParserUtils类里的不同方法,这里调用parseMessage()该方法主要处理message的消息,在该方法里分析message消息并返回packet包。返回的包将调用processPacket方法,先通知所有注册了PacketCollector的监听,接着消息(listenerExecutor.submit(newListenerNotification(packet); )传递给所有注册了PacketListener的监听。这样在activity开始之前注册的那个监听事件就会触发,从而完成了整个流程。 7以上.剩下的就是一些辅助包,很简单。比如PacketCollector 这个类,它的用处主要用来处理一些需要在发送后需要等待一个答复这样的请求。protected synchronized void processPacket(Packet packet) System.out.println(PacketCollector-processPacket); if(packet = null) return; if(packetFilter= null| packetFilter.accept(packet) while(!resultQueue.offer(packet) resultQueue.poll(); Public Packet nextResult(longtimeout) longendTime = System.currentTimeMillis() + timeout; System.out.println(nextResult); do try returnresultQueue.poll(timeout, TimeUnit.MILLISECONDS); catch(InterruptedException e) /* ignore */ while(System.currentTimeMillis() endTime); return null; 该方法就是将获取到的包,先过滤然后放到队列里,最后通过nextResult来获取包,这样就完成一个请求收一个答复。 这样整个流程就完成了,最后总结一下,如图(就这么简单0): 项目下载(只有客户端的,服务端的就是一个简单的socket接受,为了锻炼一下大家的编写代码的能力,服务器那个只能自己写咯0,其实是懒得上传了,代码很简单的)/not-code/simualteSmack.zipandroid asmack 注册 登陆 聊天 多人聊天室 文件传输XMPP协议简介XMPP协议(Extensible Messaging and PresenceProtocol,可扩展消息处理现场协议)是一种基于XML的协议,目的是为了解决及时通信标准而提出来的,最早是在Jabber上实现的。它继承了在XML环境中灵活的发展性。因此,基于XMPP的应用具有超强的可扩展性。并且XML很易穿过防火墙,所以用XMPP构建的应用不易受到防火墙的阻碍。利用XMPP作为通用的传输机制,不同组织内的不同应用都可以进行有效的通信。这篇文章有基本的介绍,/xutaozero21/article/details/4873439IMInstant Messenger,及时通信软件,就是大家使用的QQ、MSN Messenger和Gtalk等等。其中Gtalk 就是基于XMPP 协议的一个实现,其他的则不是。当前IM 几乎作为每个上网者必然使用的工具,在国外的大型企业中有一些企业级的IM应用,但是其商业价值还没完全发挥出来。设想既然XMPP 协议是一个公开的协议,那么每个企业都可以利用它来开发适合本身企业工作,提高自身生产效率的IM;甚至,你还可以在网络游戏中集成这种通信软件,不但让你可以边游戏边聊天,也可以开发出适合游戏本身的IM 应用,比如说一些游戏关键场景提醒功能,团队语音交流等等都可以基于IM来实现。 本文主要讲解在android使用xmpp协议进行即时通信,所涉及3个主要的东西,它们是openfire、smack和spark,这个三个东东结合起来就是完整的xmpp IM实现,这里简单介绍一下这3个东东在下文的作用:openfire主要是作为服务器,负责管理客户端的通信连接,以及提供客户端一些通信信息和连接信息。Smack主要是xmpp协议的实现,提供了一套很好的api,所以下面操作xmpp都是通过使用smack的api来实现,当然因为是在android里,所以使用的是asmack这个包,里面方法跟smack包差不多。Spark 是IM客户端的实现,其实就是使用了smack 的api实现的。 下图展示了三者之间的关系:(很明显这个图是偷别人的,具体是哪里我忘了,因为资料都是复制到文档后慢慢研究看的)从图上可以了解到,client 端和server端都可以通过插件的方式来进行扩展,smack是二者传递数据的媒介。 配置openfire服务器具体步骤请移步:/blog/static/1766322992010111725339587/配置成功如果以后ip地址变了,那肯定又是开不了,解决办法请移步:/HappySheepherder/article/details/4707124配置成功后,在服务器创建一个简单的用户来测试,然后安装spark,设置好服务器的ip与端口,使用刚才创建的用户登录,登录OK说明服务器成功搭建。Android IM功能(因为是测试demo,因此界面超级简陋,代码都是给出重要的一部分,剩余的可以在最后下面项目查看) 配置要求android 2.2、 asmack-jse.jar、myeclipse连接服务器在打开软件后会开始初始化,完成与openfire服务器的连接,设置一些配置static XMPPConnection.DEBUG_ENABLED=true; finalConnectionConfiguration connectionConfig =newConnectionConfiguration( host, 5222,); / Google talk / ConnectionConfiguration connectionConfig = new / ConnectionConfiguration( / , 5222, ); / connectionConfig.setSASLAuthenticationEnabled(false); ActivityMain.connection=newXMPPConnection(connectionConfig); ActivityMain.connection.DEBUG_ENABLED=true; ProviderManager pm =ProviderManager.getInstance(); configure(pm); 注册模块注册有两种方法:一种是用createAccount ,不过我测试了一下发现不能创建用户,具体原因不详,下面介绍第二种。如上图:注册成功后服务器将多了ggg用户。具体实现如下:Registration reg = newRegistration(); reg.setType(IQ.Type.SET); reg.setTo(ConnectionSingleton.getInstance().getServiceName(); reg.setUsername(username.getText().toString(); reg.setPassword(password.getText().toString(); reg.addAttribute(android, geolo_createUser_android); System.out.println(reg:+ reg); PacketFilter filter = newAndFilter(newPacketIDFilter(reg .getPacketID(), newPacketTypeFilter(IQ.class); PacketCollector collector = ConnectionSingleton.getInstance() .createPacketCollector(filter); ConnectionSingleton.getInstance().sendPacket(reg); result= (IQ) collector.nextResult(SmackConfiguration .getPacketReplyTimeout(); / Stop queuing results collector.cancel(); if(result= null) Toast.makeText(getApplicationContext(), 服, Toast.LENGTH_SHORT).show(); else if(result.getType() = IQ.Type.ERROR) if(result.getError().toString().equalsIgnoreCase( conflict(409) Toast.makeText(getApplicationContext(), 这, Toast.LENGTH_SHORT).show(); else Toast.makeText(getApplicationContext(), 注, Toast.LENGTH_SHORT).show(); else if(result.getType() = IQ.Type.RESULT) Toast.makeText(getApplicationContext(), 恭, Toast.LENGTH_SHORT).show(); 使用注册类,设置好注册的用户名密码和一些属性字段,直接设置包过滤,根据这个过滤创建一个结果集合,发送注册信息包,等待获取结果,剩余就是判断结果内容. 登录模块登录比较简单ConnectionSingleton.getInstance().connect();/ connectString account = etUsername.getText().toString();String password = etPassword.getText().toString();/ 保存用户和密码ActivityLogin.util.saveString(ACCOUNT_KEY, account);ActivityLogin.util.saveString(PASSWORD_KEY, password);ConnectionSingleton.getInstance().login(account, password);/ login/ login success System.out.println(login success);ActivityLogin.mCurrentAccount= account;System.out.println(ConnectionSingleton.getInstance() .getUser();/ 登录成功后发现在线状态Presence presence = newPresence(Presence.Type.available);ConnectionSingleton.getInstance().sendPacket(presence);/ 开始主界面Intent intent = newIntent(ActivityLogin.this, ActivityMain.class);startActivity(intent); 获取联系人模块(ActivityMain 主界面)获取联系人并将相关信息保存到一个list数组里,最后通知listview更新界面roster= ActivityMain.connection.getRoster(); public voidupdateRoster() Collection entries = roster.getEntries(); for(RosterEntry entry : entries) System.out.print(entry.getName() + - + entry.getUser() + - + entry.getType() + - + entry.getGroups().size(); Presence presence = roster.getPresence(entry.getUser(); System.out.println( - + presence.getStatus() + - + presence.getFrom(); User user = newUser(); user.setName(entry.getName(); user.setUser(entry.getUser(); user.setType(entry.getType(); user.setSize(entry.getGroups().size(); user.setStatus(presence.getStatus(); user.setFrom(presence.getFrom(); userinfos.add(user); rosterAdapter.notifyDataSetChanged(); 单人聊天模块第一次修改:在主界面点击选择一个用户,进入聊天Activity,ActivityChat先获取传过来的用户,创建聊天类并对该用户设置消息监听ChatManager chatmanager = ConnectionSingleton.getInstance() .getChatManager(); / get user Intent intent = getIntent(); String user = intent.getStringExtra(user); System.out.println(user:+ user); / new a session newChat= chatmanager.createChat(user, null); / 监听聊天消息 chatmanager.addChatListener(newChatManagerListenerEx(); / send message try newChat.sendMessage(im bird man); catch(XMPPException e) /TODOAuto-generated catch block e.printStackTrace(); 监听类public classChatManagerListenerEx implementsChatManagerListener Override public voidchatCreated(Chat chat, booleanarg1) /TODOAuto-generated method stub chat.addMessageListener(ml); public classMessageListenerEx implementsMessageListener Override public voidprocessMessage(Chat arg0, Message message) String result = message.getFrom() + :+ message.getBody(); System.out.println(result); android.os.Message msg = newandroid.os.Message(); msg.what= 0; Bundle bd = newBundle(); bd.putString(msg, result); msg.setData(bd); handler.sendMessage(msg); 所获取到的消息都是通过handler来更新UIpublicHandler handler= newHandler() Override public voidhandleMessage(android.os.Message msg) switch(msg.what) case0: String result = msg.getData().getString(msg); record.setText(record.getText() + n+ result); break; default: break; ; aaa跟bbb 的聊天第二次修改:第一次的测试,发现如果多个人之间都成为好友,那么他们之间的聊天就出现了接收不到的信息,当然在跟spark测试时,spark可以收到android端的信息,不过android客户端是收到这个信息,不过却没有显示出来,具体原因还不太清楚。因此在第二次修改我改成监听所有聊天信息包,然后再分析包的归属,分发到对应的聊天窗口。 这里就是监听到包后打印的消息,打印出了jid和消息内容public classXmppMessageManager implementsChatManagerListener privateXMPPConnection _connection; privateChatManager manager = null; public voidinitialize(XMPPConnection connection) _connection = connection; manager = _connection.getChatManager(); manager.addChatL

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论