【openfire,smack使用总结】--Smack库的使用

Smack介绍

Smack是XMPP协议的的实现库,Smack库易于使用,仅仅几行代码就能实现客户端连接,登陆,发送即时消息。但是由于使用XMPP协议,所以不适合用在高并发的场合。

Smack的使用

本文使用的是4.1.9版本的Smack库来演示,Smack的官方下载地址:http://www.igniterealtime.org/projects/smack/。
下载下来后根据需求进行引入。比如,android平台,要额外引入smack-android-4.1.9.jarsmack-android-extensions-4.1.9库,而且,需要在使用之前进行初始化:

AndroidSmackInitializer androidSmackInitializer=new AndroidSmackInitializer();
androidSmackInitializer.initialize();

而且值得注意的是:Android网络连接需要在子线程中进行。

如果运行在PC端则不需要以上要求。

连接服务器

//配置一个TCP连接
XMPPTCPConnectionConfiguration config =XMPPTCPConnectionConfiguration.builder()
        .setServiceName("openfire")//设置服务器名称,可以到openfire服务器管理后台查看
        .setHost("localhost")//设置主机
        .setPort(5222)//设置端口
        .setConnectTimeout(20000)//设置连接超时时间
       .setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)//设置是否启用安全连接
        .build();
XMPPTCPConnection connection = new XMPPTCPConnection(config);//根据配置生成一个连接
connection.connect();//连接到服务器

也可以设置监听连接的状态

connection.addConnectionListener(newConnectionListener() {
       @Override
       public void connected(XMPPConnection connection) {
           //已连接上服务器
       }
 
       @Override
       public void authenticated(XMPPConnection connection, boolean resumed) {
           //已认证
       }
 
       @Override
       public void connectionClosed() {
           //连接已关闭
       }
 
       @Override
       public void connectionClosedOnError(Exception e) {
           //关闭连接发生错误
       }
 
       @Override
       public void reconnectionSuccessful() {
           //重连成功
       }
 
       @Override
       public void reconnectingIn(int seconds) {
           //重连中
       }
 
       @Override
       public void reconnectionFailed(Exception e) {
           //重连失败
       }
    });

注册账户

HashMap attributes =new HashMap();//附加信息
AccountManager.sensitiveOperationOverInsecureConnectionDefault(true);
AccountManager.getInstance(connection).createAccount(username,password, attributes);//创建一个账户,username和password分别为用户名和密码

账户登录

connection.login(username,password);// username和password分别为用户名和密码

设置用户状态

//设置成在线,这里如果改成unavailable则会显示用户不在线
Presence presence = new Presence(Presence.Type.available);
presence.setStatus("在线");
connection.sendStanza(presence);//发送Presence包

发送文本消息

ChatManager chatManager= ChatManager.getInstanceFor(connection);//从连接中得到聊天管理器
Chat chat= chatManager.createChat(username);//创建一个聊天,username为对方用户名
chat.sendMessage(msg);//发送一个文本消息,msg为String类型的文本消息,即使没加为好友也能进行聊天

发送消息也可以添加消息体!比如加个字体颜色字段

Message msg=new Message();
msg.setBody("你好啊");//消息主体
msg.addBody("textColor","#f00");//字体颜色字段
chat.sendMessage(msg);//发送一个文本消息

监听文本消息

chatManager.addChatListener(new ChatManagerListener() {
                /**
                 * @param chat
                 * @param b    消息是否来自本地用户
                 */
                @Override
                public void chatCreated(Chatchat, boolean b) {
                    if (!b) {
                       chat.addMessageListener(chatMessageListener);
                    }
                }
           });
    private static ChatMessageListener chatMessageListener=new ChatMessageListener() {
           @Override
           public void processMessage(Chat chat, final Message message) {
               String msg=message. getBody();
              //在此处可以处理接收到的消息
             //………
             //如果在发送的时候有自定义消息体,比如我们发送的时候添加了一个名为“textColor”的消息体,在这里就可以根据名称取出
            String color=message. getBody("textColor");
           }
});

发送自定义IQ包

应用场景:当我们想扩展自己聊天软件的功能的时候,就会用到自定义数据包。比如,实现匹配陌生人聊天,与服务进行通信等。

在Smack中,要想发送IQ包。先写一个类,然后继承IQ类,然后重写getIQChildElementBuilder方法,在这个方法里拼接我们的IQ包。

比如:

@Override
       protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
              //TODO Auto-generated method stub
              xml.xmlnsAttribute("match:info");//设置xml的命名空间
              xml.attribute("type","iq");//设置字段
              xml.rightAngleBracket();//插入一个“>”
              xml.element("data","其他数据");//插入一个节点其他数据
              //注意!这里不要调用closeEmptyElement
              //xml.closeEmptyElement();
              returnxml;
       }

然后就可以发送了,比如我们刚才创建的继承IQ类的类是NonChatMsgIQ:

NonChatMsgIQ msg=new NonChatMsgIQ("info");//设置iq节点的子节点的名称
msg.setFrom(connection.getUser());//设置包的来源
msg.setTo("openfire/MatchUserPlugin");//设置包发送的去处
connection.sendStanza(msg);//发送

msg.setTo("openfire/MatchUserPlugin");中的openfire/MatchUserPlugin,openfire是指服务器的名称,MatchUserPlugin是插件的名称,如果要发送IQ包到openfire的某个插件,请遵循这个规则。而不要写成主机地址!

接收自定义的IQ包

在服务端我们也可能自定义IQ包,然后发给客户端,或者客户端与客户端之间相互发包。所以来看一下怎么接收发来的自定义的IQ包。(IQ是Stanza子类,在文中看到Stanza不要奇怪。)

首先设置过滤器和监听器。

StanzaFilter filter =new AndFilter( new StanzaTypeFilter(NonChatMsgIQ.class)
,new ToFilter(connection.getUser()));//配置过滤器
connection.addSyncStanzaListener(stanzaListener,filter);//设置监听器
private  StanzaListener stanzaListener=new StanzaListener() {
       @Override
       public void processPacket(Stanza packet) {
           // TODO Auto-generated method stub
          //在这里就可以处理出去和进来的数据包
          
       }
   };

过滤器有这几种:

StanzaIdFilter

根据包的ID过滤

StanzaTypeFilter

根据包的类型过滤

AndFilter

按逻辑”并”过滤

OrFilter

按逻辑”或”过滤

NotFilter

按逻辑“非”过滤

ToFilter

按包的发送方向过滤

FromMatchesFilter

按包的来源过滤

 

设置IQProvider,IQProvider指定怎么解析你的自定义IQ类,不指定IQProvider,就会导致过滤包时发生错误,因为Smack不知道该如何解析你的IQ包。

首先编写一个类,该类继承自IQProvider,然后重写parse方法。这个方法返回一个IQ,组装好后直接返回即可。

       @Override
       public NonChatMsgIQ parse(XmlPullParser parser, int initialDepth)
                     throwsXmlPullParserException, IOException, SmackException {
              //TODO Auto-generated method stub
              NonChatMsgIQ msg=new NonChatMsgIQ("info");
              msg.setMsgType(parser.getAttributeValue(0));
              return msg;
       }

类编写完毕,就往ProviderManager里添加我们的IQProvider。

ProviderManager.addIQProvider("info","match:info", new NonChatMsgIQProvider());

断线重连

作为即时聊天软件,短线重连太重要了。在Smack设置断线重连也很简单。

ReconnectionManager reconnectionManager=ReconnectionManager.getInstanceFor(connection);
reconnectionManager.enableAutomaticReconnection();

断开与服务器的连接

connection.disconnect();


文件传输

在Smack中传输文件很简单,接收文件的一端调用addFileTransferListener方法添加文件文件接收事件,发送文件的一端调用sendFile或者sendStream方法发送文件。而且两端不需要提前成为好友。

发送文件:

FileTransferManager fileTransferManager= FileTransferManager.getInstanceFor(connection);

OutgoingFileTransfer outgoingFileTransfer=fileTransferManager.createOutgoingFileTransfer(userId);
outgoingFileTransfer.sendFile(fileName,"");

接收文件:

FileTransferManager fileTransferManager= FileTransferManager.getInstanceFor(connection);
fileTransferManager.addFileTransferListener(new FileTransferListener() {
    @Override
    public void fileTransferRequest(FileTransferRequest fileTransferRequest) {
        IncomingFileTransfer incomingFileTransfer= fileTransferRequest.accept();
        InputStream in=incomingFileTransfer.recieveFile();//开始接收文件
        String fileName=incomingFileTransfer. getFileName();
        final String dir="/sdcard/fileRec";
        FileOutputStream fileOutputStream=new FileOutputStream(dir+File.separator+fileName);
        byte[] buf=new byte[1024];
        int len=-1;
        int cur=0;
        while ((len=in.read(buf))!=-1)
        {
            fileOutputStream.write(buf,0,len);
            fileOutputStream.flush();
            cur+=len; 
        }
	fileOutputStream.close();
    }
});

总结

Smack使用简单,适合中小型聊天软件或者社区软件使用。更多内容可以去查看Smack官方文档,官方API文档。

你可能感兴趣的:(Openfire/Smack)