Android IM之基于Openfire+Smack的聊天服务器的搭建与测试

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sbsujjbcy/article/details/48734539

XMPP协议(Extensible Messaging and PresenceProtocol,可扩展消息处理现场协议)是一种基于XML的协议,目的是为了解决及时通信标准而提出来的,最早是在Jabber上实现的。它继承了在XML环境中灵活的发展性。因此,基于XMPP的应用具有超强的可扩展性。并且XML很易穿过防火墙,所以用XMPP构建的应用不易受到防火墙的阻碍。利用XMPP作为通用的传输机制,不同组织内的不同应用都可以进行有效的通信。

先来了解几个概念

  • Openfire主要是作为服务器,负责管理客户端的通信连接,以及提供客户端一些通信信息和连接信息。

  • Smack主要是xmpp协议的实现,提供了一套很好的api,所以下面操作xmpp都是通过使用Smack的api来实现,从4.1.0开始,它就支持Android了,所以我们直接使用Smack即可,当然在这不支持之前是使用Asmack这个包的,里面方法跟smack包差不多。

  • Spark 是IM客户端的实现,其实就是使用了Smack 的api实现的。

以上三个中第一个和第三个的下载地址见http://www.igniterealtime.org/downloads/index.jsp#openfire,我们需要将他们下载下来,这里我们下载windows版

这里写图片描述

第二个是一套基于XMPP实现的API,我们直接引用其即可,在Android Studio中,我们直接在gradle中添加依赖即可。

    compile 'org.igniterealtime.smack:smack-android-extensions:4.1.4'
    compile 'org.igniterealtime.smack:smack-tcp:4.1.4'

然后我们需要添加网络权限

    <uses-permission android:name="android.permission.INTERNET" />

接下来我们先不管android端,我们先进行两个软件的安装。首先安装openfire.

点击安装包打开进行初始化

这里写图片描述

选择语言,这里选择中文

这里写图片描述

确定后再点下一步

这里写图片描述

同意许可点击下一步

这里写图片描述

选择安装目录点击下一步,这里是默认目录

这里写图片描述

继续下一步

这里写图片描述

耐心等待文件解压完成

这里写图片描述

点击完成后运行Openfire

这里写图片描述

运行成功后点击Launch Admin进入后台完成剩下的安装工作

这里写图片描述

选择语言

这里写图片描述
服务器配置,我们将域修改为本机的局域网IP地址

我们需要获得我们电脑的IP地址。

这里写图片描述

获得的IP地址为10.0.0.24,将域修改为这个值

这里写图片描述

数据库我们选择使用外部数据库,所以勾选第一个

这里写图片描述

接下来就是一些值,第一项的下拉选择mysql,之后值会被填充。接下来我们就需要在mysql中添加一个数据库。

这里写图片描述

这里假设你的本地有mysql服务器,打开后台,添加一个用户,勾选创建与用户名同名的数据库并授予所有权限

这里写图片描述

把database name和hostname修改成对应的值,用户名和密码为你刚才mysql中创建的用户和密码

这里写图片描述

选择初始设置

这里写图片描述

设置openfire管理员账号密码,这里账号设置为admin,密码自己设置

这里写图片描述

点击登录到管理控制台

这里写图片描述

进入到后台,输入账号密码进行登陆

这里写图片描述

登陆成功后就是后台了

这里写图片描述

然后安装Spark,点击下载的安装包

这里写图片描述

选择安装目录

这里写图片描述

点击下一步

这里写图片描述

继续点击下一步

这里写图片描述

等待安装完成

这里写图片描述

点击finish运行spark

这里写图片描述

使用我们的管理员账号admin进行登陆,服务器为本地,127.0.0.1

这里写图片描述

如果登陆成功了就会出现下面的界面

这里写图片描述

然后我们添加两个测试账号,在openfire后台,输入这些信息进行添加用户

这里写图片描述

添加了两个测试账号,分别为test和test1

这里写图片描述

接下来最重要的事就是Android端了,在这之前,我们需要让我们的手机和电脑出于同一个局域网内,如果你使用的是模拟器,那么,不存在这个问题。

获得的IP地址为10.0.0.24,接下来就是编写代码进行登陆了。

获得一个连接

 private XMPPTCPConnection getConnection(){
        String server="10.0.0.24";
        int port=5222;
        XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder();
        builder.setServiceName(server);
        builder.setHost(server);
        builder.setPort(port);
        builder.setCompressionEnabled(false);
        builder.setDebuggerEnabled(true);
        builder.setSendPresence(true);
        builder.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
        XMPPTCPConnection connection = new XMPPTCPConnection(builder.build());
        return connection;
    }

初始化变量

private EditText account, password,to,content;
private Button login,logout,send;
private  XMPPTCPConnection connection;

connection=getConnection();

account = (EditText) findViewById(R.id.account);
password = (EditText) findViewById(R.id.password);
to = (EditText) findViewById(R.id.to);
content = (EditText) findViewById(R.id.content);
login = (Button) findViewById(R.id.login);
logout = (Button) findViewById(R.id.logout);
send = (Button) findViewById(R.id.send);
login.setOnClickListener(this);
logout.setOnClickListener(this);
send.setOnClickListener(this);

对应的点击事件的实现,也就是登陆,登出,发送消息的逻辑

@Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.login:{
                final String a = account.getText().toString();
                final String p = password.getText().toString();
                if (TextUtils.isEmpty(a) || TextUtils.isEmpty(p)) {
                    Toast.makeText(getApplicationContext(), "账号或密码不能为空", Toast.LENGTH_LONG).show();
                    return;
                }
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            connection.connect();
                            connection.login(a, p);
                            Presence presence = new Presence(Presence.Type.available);
                            presence.setStatus("我是在线状态");
                            connection.sendStanza(presence);
                            ChatManager chatmanager = ChatManager.getInstanceFor(connection);
                            chatmanager.addChatListener(new ChatManagerListener() {
                                @Override
                                public void chatCreated(Chat chat, boolean createdLocally) {
                                    chat.addMessageListener(new ChatMessageListener() {
                                        @Override
                                        public void processMessage(Chat chat, Message message) {
                                            String content=message.getBody();
                                            if (content!=null){
                                                Log.e("TAG", "from:" + message.getFrom() + " to:" + message.getTo() + " message:" + message.getBody());
                                                android.os.Message message1= android.os.Message.obtain();
                                                message1.what=1;
                                                message1.obj="收到消息:" + message.getBody()+" 来自:"+message.getFrom();
                                                mHandler.sendMessage(message1);
                                            }

                                        }
                                    });
                                }
                            });
                        } catch (SmackException e) {
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        } catch (XMPPException e) {
                            e.printStackTrace();
                        }

                    }
                }).start();
                break;
            }
            case R.id.logout:
                connection.disconnect();
                break;
            case R.id.send:
                final String t = to.getText().toString();
                final String c = content.getText().toString();
                if (TextUtils.isEmpty(t)||TextUtils.isEmpty(c)) {
                    Toast.makeText(getApplicationContext(), "接收方或内容", Toast.LENGTH_LONG).show();
                    return;
                }

                try {
                    ChatManager chatmanager = ChatManager.getInstanceFor(connection);
                    Chat mChat = chatmanager.createChat(t+"@10.0.0.24");
                    mChat.sendMessage(c);
                }
                catch (SmackException.NotConnectedException e) {
                    e.printStackTrace();
                }
                break;
        }

    }

收到消息后需要在主线程里操作,简单的Toast一下

private Handler mHandler=new Handler(){
    @Override
    public void handleMessage(android.os.Message msg) {
        switch (msg.what){
            case 1:
                Toast.makeText(getApplicationContext(),msg.obj+"",Toast.LENGTH_SHORT).show();
                break;
        }
        super.handleMessage(msg);
    }
};

这时候如果你使用测试账号进行登陆,你会发现登陆不了,会报一个错误

这里写图片描述

解决方法也比较简单,到Openfire的安装目录中,寻找conf/openfire.xml文件

这里写图片描述

在最后一个节点闭合前加入代码

  <sasl>
    <mechs> PLAIN </mechs>
  </sasl>

这里写图片描述

重启OpenFire,这时候你会发现成功登陆了,并能正常的设置用户的在线状态了

这里写图片描述

将我们的Spark使用测试账号test1登陆,Android端使用test登陆,测试消息是否能成功送到。

这里写图片描述

很简单的我们把整个流程走了一遍,后面如果有机会的话再继续研究下这个东西,其实它的功能是很强大的。

最后贴一下Android的源码。

http://download.csdn.net/detail/sbsujjbcy/9139479

展开阅读全文

没有更多推荐了,返回首页