2.xmpp协议,openfire使用

目录

即时通信( Instant Messaging,简称 IM) 

XMPP协议背景:

XMPP服务端: openfire服务端

官网 http://www.openfire.net.cn/1329.html

插件开发

XMPP客户端:Spark



即时通信( Instant Messaging,简称 IM) 

像qq.微信 ,  即时通讯需要 服务器, 客户端, 服务器与客户端通讯

一般支持私聊,群聊,离线消息等等


XMPP协议背景:

即时通讯没有统一的标准【各用各的通讯协议,就像qq无法给微信发消息】,无法实现互联互通,  XMPP协议就是这样的一个协议 (支持文本、视频、文件等的传输) , 

 XMPP 协议是以 XML 为基础的 

<message from="11@myopenfire.com" to="22@myopenfire.com">11发给22的消息</message>

也就是说 XMPP 协议不仅可以用在人与人之间的交流,而且可以实现软件与软件或软件与人之间的交流

XMPP 中定义了三个角色, 服务器,客户端,网关


XMPP服务端: openfire服务端

官网 http://www.openfire.net.cn/1329.html

Openfire 是基于XMPP 协议的IM 的服务器端的一个实现

参考 http://myopenfire.com/article/articledir/1

Openfire是一个Java应用程序, 

 Openfire采用内置的jetty作web服务器,在启动AdminConsolePlugin插件时调用startup()方法启动jetty服务器,9090为其明文端口,9091为其加密端口。 启动成功后, 可以从网站进入http://ip:9090 openfire管理控制台

设置服务端端口,客户端连接设置,策略设置,离线消息的存储

 

openfire需要用到数据库:

ofGroup (用户组的数据)

ofGroupUser (组成员)

ofUser (用户数据)

ofOffline (离线邮件存储)

 

 

插件开发

下载源码,生成eclipse项目,添加项目依赖的Jar包,运行openfire

 


XMPP客户端:Spark

这里就不介绍spark了, 这个spark软件的通讯核心是用Smack, 主要介绍Smack的开发使用

Smack 是一个XMPP 协议的Java 实现,提供一套可扩展的API 

你需要添加smack相关的jar包:

smack.jar
smackx.jar

org.jivesoftware.smack.

Spark 提供了客户端一个基本的实现,并提出了一个很好的插件架构

服务器通讯要用自定义证书的话要用自定义的SSLConent,说白点就是不验证证书是否可信。这玩意不知道使用有CA签名的证书会不会有这问题。

例: java客户端发送消息

package com.openfire.client;

import java.io.IOException;
import java.util.Scanner;

import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.chat.Chat;
import org.jivesoftware.smack.chat.ChatManager;
import org.jivesoftware.smack.chat.ChatManagerListener;
import org.jivesoftware.smack.chat.ChatMessageListener;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;

/**
 * Hello XMPP!
 *
 */
public class App extends Thread 
{
    void say() {
    };
    
    public static void main( String[] args ) throws SmackException, IOException, XMPPException, InterruptedException
    {
            // 对连接的配置
            XMPPTCPConnectionConfiguration.Builder builder = XMPPTCPConnectionConfiguration.builder();
            builder.setUsernameAndPassword("admin", "123456");
            builder.setServiceName("ww110"); //openfire服务端名字,登录管理后台可查看
            builder.setHost("192.168.0.110");
            builder.setPort(5222);
        
            // 不加这行会报错,因为没有证书
            builder.setSecurityMode(SecurityMode.disabled);
            //SASLAuthentication.supportSASLMechanism("PLAIN",0); 
            builder.setDebuggerEnabled(true);
            XMPPTCPConnectionConfiguration config = builder.build();
            
            // 建立连接并登陆
            AbstractXMPPConnection c = new XMPPTCPConnection(config);
            c.addPacketSendingListener(new StanzaListener() {
                @Override
                public void processPacket(Stanza st) throws NotConnectedException {
                    System.out.println("in StanzaListener:" + st.getFrom());
                }
            }, new StanzaFilter() {
                @Override
                public boolean accept(Stanza st) {
                    System.out.println("in StanzaFilter:" + st.getFrom());
                    return false;
                }
            });

            c.connect();
            c.login();
            
            ChatManager chatManager = ChatManager.getInstanceFor(c);
            chatManager.addChatListener(new ChatManagerListener() {
                @Override
                public void chatCreated(Chat cc, boolean bb) {
                    // 当收到来自对方的消息时触发监听函数
                    cc.addMessageListener(new ChatMessageListener() {
                        @Override
                        public void processMessage(Chat cc, Message mm) {
                            System.out.println("app2收到消息:" + cc + mm.getBody());
                        }
                    });
                }
            });

            while (true) {
                sleep(2000);
               //每2秒给new1用户发消息
                Chat chat = chatManager.createChat("new1@ww110");
                chat.getThreadID(); Message msg = new Message();
                msg.setBody("你好,我是机器人"); 
                chat.sendMessage(msg); 
            } 
    } 
}
import java.util.Collection;
import java.util.Iterator;
import javax.net.SocketFactory;
import org.jivesoftware.smack.AccountManager;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManager;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Session;
import org.jivesoftware.smack.packet.Message.Type;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
 
/**
 * <b>function:</b> 利用Smack框架完成 XMPP 协议通信
 */
public class SmackXMPPTest {
 
	/** 连接器 */
    private Connection connection;
	/** 连接参数 */
    private ConnectionConfiguration config;
    /** openfire服务器address */
    private final static String serverIp = "127.0.0.1";
	
    /**
     * <b>function:</b> 消息处理方法
     */
    private final void fail(Object o) {
        if (o != null) {
            System.out.println(o);
        }
    }
    private final void fail(Object o, Object... args) {
        if (o != null && args != null && args.length > 0) {
            String s = o.toString();
            for (int i = 0; i < args.length; i++) {
                String item = args[i] == null ? "" : args[i].toString();
                if (s.contains("{" + i + "}")) {
                    s = s.replace("{" + i + "}", item);
                } else {
                    s += " " + item;
                }
            }
            System.out.println(s);
        }
    }
    
    /**
     * <b>function:</b> 初始Smack对openfire服务器链接的基本配置
     */
    @Before
    public void init() {
        try {
            /** 5222是openfire服务器默认的通信端口,可以登录http://ip:9090/到管理员控制台查看客户端到服务器端口 */
            config = new ConnectionConfiguration(serverIp, 5222);
            config.setCompressionEnabled(true); /** 是否启用压缩 */ 
            config.setSASLAuthenticationEnabled(true);/** 是否启用安全验证 */
            config.setDebuggerEnabled(false);/** 是否启用调试 */
            //config.setReconnectionAllowed(true);
            //config.setRosterLoadedAtLogin(true);
            //config.setSendPresence(true);
			
            connection = new XMPPConnection(config);
            /** 建立连接 */
            connection.connect();
        } catch (XMPPException e) {
            e.printStackTrace();
        }
        fail(connection);
        fail(connection.getConnectionID());
    }
	
    /**
     * <b>function:</b> 销毁连接器
     */
    @After
    public void destory() {
        if (connection != null) {
            connection.disconnect();
            connection = null;
        }
    }
    
    /**
     * <b>function:</b> XMPPConnection 获取连接基本信息
     */
    @Test
    public void testConnection() {
        AccountManager accountManager = connection.getAccountManager();
        for (String attr : accountManager.getAccountAttributes()) {
            fail("AccountAttribute: {0}", attr);
        }
        fail("AccountInstructions: {0}", accountManager.getAccountInstructions());
        fail("isConnected:", connection.isConnected());/** 是否链接 */
        fail("isAnonymous:", connection.isAnonymous());
        fail("isAuthenticated:", connection.isAuthenticated());/** 是否有权限 */
        fail("isSecureConnection:", connection.isSecureConnection());
        fail("isUsingCompression:", connection.isUsingCompression());/** 是否使用压缩 */
    }
    
    /**
     * <b>function:</b> 用户管理器:创建用户,修改密码
     */
    @Test
    public void testAccountManager() {
        AccountManager accountManager = connection.getAccountManager();
        for (String attr : accountManager.getAccountAttributes()) {
            fail("AccountAttribute: {0}", attr);
        }
        fail("AccountInstructions: {0}", accountManager.getAccountInstructions());
        fail("supportsAccountCreation: {0}", accountManager.supportsAccountCreation());
		 /** 可以在管理员控制台页面http://ip:9090/user-summary.jsp查看用户/组的相关信息,来查看是否成功创建用户 */
        try {
            /** 创建一个用户boy,密码为boy */
            accountManager.createAccount("boy", "boy");
            /** 修改密码 */
            accountManager.changePassword("abc");
        } catch (XMPPException e) {
            e.printStackTrace();
        }
    }
    /**
     * <b>function:</b> 用户登陆
     */
    @Test
    public void testUser() {
        try {
            /** 用户登陆,用户名、密码 */
            connection.login("boy", "boy");
        } catch (XMPPException e) {
            e.printStackTrace();
        }
        fail("User:", connection.getUser());/** 获取当前登陆用户 */
        Roster roster = connection.getRoster();/** 所有用户组 */
        /** 好友用户组,
		用Spark添加用户好友,这里就可以查询到相关的数据 */
        Collection<RosterEntry> rosterEntiry = roster.getEntries();
        Iterator<RosterEntry> iter = rosterEntiry.iterator();
        while (iter.hasNext()) {
            RosterEntry entry = iter.next();
            fail("组: {0}, 名: {1}, 状态: {2}, 类型: {3}, 用户: {4}", entry.getGroups(), entry.getName(), entry.getStatus(), entry.getType(), entry);
        }
        
        /** 未处理、未验证的好友 */
        Collection<RosterEntry> unfiledEntries = roster.getUnfiledEntries();
        iter = unfiledEntries.iterator();
        while (iter.hasNext()) {
            RosterEntry entry = iter.next();
            fail("组: {0}, 名: {1}, 状态: {2}, 类型: {3}, 用户: {4}", entry.getGroups(), entry.getName(), entry.getStatus(), entry.getType(), entry);
        }
    }
    /**
     * <b>function:</b> 更改登录状态,向其他用户发消息
     */
    @Test
    @SuppressWarnings("static-access")
    public void testPacket() {
        try {
            connection.login("testUser", "testPassword");
        } catch (XMPPException e) {
            e.printStackTrace();
        }
        
        //Packet packet = new Data(new DataPacketExtension("jojo@" + serverIp, 2, "this is a message"));
        //connection.sendPacket(packet);
        
        /** 更改用户状态,
		available=true表示在线,false表示离线,
		status状态签名;
		登陆后在Spark客户端软件中就可以看到你登陆的状态 */
        Presence presence = new Presence(Presence.Type.available);
        presence.setStatus("我在线了");
        connection.sendPacket(presence);
        
        Session session = new Session();
        String sessid = session.nextID();
        connection.sendPacket(session);
		
        /** 向user2@127.0.0.1发送聊天消息,Spark登陆的jojo用户就可以接收到消息
         **/
        /** Type.chat 表示聊天,groupchat多人聊天,error错误,headline在线用户; */
        Message message = new Message("user2@" + serverIp, Type.chat);
        //Message message = new Message(sessid, Type.chat);
        message.setBody("user2, 我是testUser!");
        connection.sendPacket(message);
        
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
     * <b>function:</b> 更改登录状态,向其他用户发消息,监听其他用户发过来的信息
     */
    @Test
    public void testChatManager() {
        /** 设置状态 */
        try {
            connection.login("testUser", "testPassword");
        } catch (XMPPException e) {
            e.printStackTrace();
        }
        
        /** 设置状态 */
        Presence presence = new Presence(Presence.Type.available);
        presence.setStatus("我在线了");
        connection.sendPacket(presence);
        
        /** 获取当前登陆用户的聊天管理器 */
        ChatManager chatManager = connection.getChatManager();
        /** 为指定用户创建一个chat,MyMessageListeners用于监听对方发过来的消息  */
        Chat chat = chatManager.createChat("user2@" + serverIp, new MyMessageListeners());
        try {
            /** 发送消息 */
            chat.sendMessage("h!~ user2……");
            
            /** 用message对象发送消息 */
            Message message = new Message();
            message.setBody("message");
            message.setProperty("color", "red");
            chat.sendMessage(message);
        } catch (XMPPException e) {
            e.printStackTrace();
        }
        try {
            Thread.sleep(1000 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * <b>function:</b> 消息监听器,用户监听对方发送的消息,也可以想对方发送消息
     */
    class MyMessageListeners implements MessageListener {
        public void processMessage(Chat chat, Message message) {
            try {
                /** 发送消息 */
                chat.sendMessage("dingding……" + message.getBody());
            } catch (XMPPException e) {
                e.printStackTrace();
            }
            /** 接收消息 */
            fail("From: {0}, To: {1}, Type: {2}, Sub: {3}", message.getFrom(), message.getTo(), message.getType(), message.toXML());
            fail("body: ", message.getBody());
        }
    }
}

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xyc1211

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值