Openfire 采用Java开发,开源的实时协作(RTC)服务器基于XMPP(Jabber)协议。Openfire安装和使用都非常简单,并利用Web进行管理。单台服务器可支持上万并发用户。
好友界面
功能界面
聊天界面
服务端可以用本服务器测试,地址:www.it72.com。如果想自己搭可在本博客其它XMPP文章找到相关搭建资料。
实现了用户注册,登录,添加好友,聊天核心功能。可正常聊天!
核心通讯代码:
package com.lee.xqq.control; import java.io.ByteArrayInputStream; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.jivesoftware.smack.Connection; import org.jivesoftware.smack.ConnectionConfiguration; import org.jivesoftware.smack.ConnectionCreationListener; import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.PacketCollector; import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.Roster; import org.jivesoftware.smack.RosterEntry; import org.jivesoftware.smack.RosterGroup; import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.PacketFilter; import org.jivesoftware.smack.filter.PacketIDFilter; import org.jivesoftware.smack.filter.PacketTypeFilter; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Presence.Type; import org.jivesoftware.smack.packet.Registration; import org.jivesoftware.smack.provider.PrivacyProvider; import org.jivesoftware.smack.provider.ProviderManager; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.Form; import org.jivesoftware.smackx.GroupChatInvitation; import org.jivesoftware.smackx.PrivateDataManager; import org.jivesoftware.smackx.ReportedData; import org.jivesoftware.smackx.ReportedData.Row; import org.jivesoftware.smackx.bytestreams.socks5.provider.BytestreamsProvider; import org.jivesoftware.smackx.packet.ChatStateExtension; import org.jivesoftware.smackx.packet.LastActivity; import org.jivesoftware.smackx.packet.OfflineMessageInfo; import org.jivesoftware.smackx.packet.OfflineMessageRequest; import org.jivesoftware.smackx.packet.SharedGroupsInfo; import org.jivesoftware.smackx.packet.VCard; import org.jivesoftware.smackx.provider.AdHocCommandDataProvider; import org.jivesoftware.smackx.provider.DataFormProvider; import org.jivesoftware.smackx.provider.DelayInformationProvider; import org.jivesoftware.smackx.provider.DiscoverInfoProvider; import org.jivesoftware.smackx.provider.DiscoverItemsProvider; import org.jivesoftware.smackx.provider.MUCAdminProvider; import org.jivesoftware.smackx.provider.MUCOwnerProvider; import org.jivesoftware.smackx.provider.MUCUserProvider; import org.jivesoftware.smackx.provider.MessageEventProvider; import org.jivesoftware.smackx.provider.MultipleAddressesProvider; import org.jivesoftware.smackx.provider.RosterExchangeProvider; import org.jivesoftware.smackx.provider.StreamInitiationProvider; import org.jivesoftware.smackx.provider.VCardProvider; import org.jivesoftware.smackx.provider.XHTMLExtensionProvider; import org.jivesoftware.smackx.search.UserSearch; import org.jivesoftware.smackx.search.UserSearchManager; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import com.lee.xqq.ChatActivity; import com.lee.xqq.MainActivity; import com.lee.xqq.SplashActivity; import com.lee.xqq.base.BroadSender; import com.lee.xqq.base.MLog; import com.lee.xqq.item.XUserItem; import com.lee.xqq.net.HttpResult; import com.lee.xqq.net.HttpUtil; import com.lee.xqq.util.CachedThreadPool; /** * 所有的数据控制,逻辑可以在这里实现 * */ public class DataUtils implements ConnectionListener, ConnectionCreationListener, PacketListener { private static DataUtils instance; private Connection connection; private static String host; private static int port; private String user; private DataUtils() { } public void setHost(String host, int port) { DataUtils.host = host; DataUtils.port = port; } public static DataUtils getInstance() { if (instance == null) instance = new DataUtils(); return instance; } public Connection getConnection() { return connection; } public String getUser() { return user; } public void requestBaidu() { CachedThreadPool.execute(new Runnable() { @Override public void run() { // TODO Auto-generated method stub HttpUtil httpUtil = HttpUtil.requestText( "http://www.baidu.com", "GET"); HttpResult result = httpUtil.getResponse(); if (result.getCode() == 200) { // 向界面发送接收广播 } } }); } public void initXMPP() { CachedThreadPool.execute(new Runnable() { @Override public void run() { // TODO Auto-generated method stub connectXmppServer(); } }); } private void connectXmppServer() { ConnectionConfiguration config = new ConnectionConfiguration(host, port); /** 是否启用安全验证 */ config.setSASLAuthenticationEnabled(false); config.setReconnectionAllowed(true);// 断线重连 /** 是否启用调试 */ // config.setDebuggerEnabled(true); /** 创建connection链接 */ try { Connection.addConnectionCreationListener(this); configure(ProviderManager.getInstance()); connection = new XMPPConnection(config); /** 建立连接 */ connection.connect(); connection.addConnectionListener(this); PacketTypeFilter filter = new PacketTypeFilter(Packet.class); connection.addPacketListener(this, filter); } catch (XMPPException e) { e.printStackTrace(); MLog.makeText("服务器连接失败"); } } /** * Android读不到/META-INF下的配置文件,需要手工配置。 * * @param pm */ private void configure(ProviderManager pm) { // Private Data Storage pm.addIQProvider("query", "jabber:iq:private", new PrivateDataManager.PrivateDataIQProvider()); // Time try { pm.addIQProvider("query", "jabber:iq:time", Class.forName("org.jivesoftware.smackx.packet.Time")); } catch (ClassNotFoundException e) { e.printStackTrace(); } // Roster Exchange pm.addExtensionProvider("x", "jabber:x:roster", new RosterExchangeProvider()); // Message Events pm.addExtensionProvider("x", "jabber:x:event", new MessageEventProvider()); // Chat State pm.addExtensionProvider("active", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); pm.addExtensionProvider("composing", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); pm.addExtensionProvider("paused", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); pm.addExtensionProvider("inactive", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); pm.addExtensionProvider("gone", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider()); // XHTML pm.addExtensionProvider("html", "http://jabber.org/protocol/xhtml-im", new XHTMLExtensionProvider()); // Group Chat Invitations pm.addExtensionProvider("x", "jabber:x:conference", new GroupChatInvitation.Provider()); // Service Discovery # Items pm.addIQProvider("query", "http://jabber.org/protocol/disco#items", new DiscoverItemsProvider()); // Service Discovery # Info pm.addIQProvider("query", "http://jabber.org/protocol/disco#info", new DiscoverInfoProvider()); // Data Forms pm.addExtensionProvider("x", "jabber:x:data", new DataFormProvider()); // MUC User pm.addExtensionProvider("x", "http://jabber.org/protocol/muc#user", new MUCUserProvider()); // MUC Admin pm.addIQProvider("query", "http://jabber.org/protocol/muc#admin", new MUCAdminProvider()); // MUC Owner pm.addIQProvider("query", "http://jabber.org/protocol/muc#owner", new MUCOwnerProvider()); // Delayed Delivery pm.addExtensionProvider("x", "jabber:x:delay", new DelayInformationProvider()); // Version try { pm.addIQProvider("query", "jabber:iq:version", Class.forName("org.jivesoftware.smackx.packet.Version")); } catch (ClassNotFoundException e) { // Not sure what's happening here. e.printStackTrace(); } // VCard pm.addIQProvider("vCard", "vcard-temp", new VCardProvider()); // Offline Message Requests pm.addIQProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageRequest.Provider()); // Offline Message Indicator pm.addExtensionProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageInfo.Provider()); // Last Activity pm.addIQProvider("query", "jabber:iq:last", new LastActivity.Provider()); // User Search pm.addIQProvider("query", "jabber:iq:search", new UserSearch.Provider()); // SharedGroupsInfo pm.addIQProvider("sharedgroup", "http://www.jivesoftware.org/protocol/sharedgroup", new SharedGroupsInfo.Provider()); // JEP-33: Extended Stanza Addressing pm.addExtensionProvider("addresses", "http://jabber.org/protocol/address", new MultipleAddressesProvider()); // FileTransfer pm.addIQProvider("si", "http://jabber.org/protocol/si", new StreamInitiationProvider()); pm.addIQProvider("query", "http://jabber.org/protocol/bytestreams", new BytestreamsProvider()); // Privacy pm.addIQProvider("query", "jabber:iq:privacy", new PrivacyProvider()); pm.addIQProvider("command", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider()); pm.addExtensionProvider("malformed-action", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.MalformedActionError()); pm.addExtensionProvider("bad-locale", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadLocaleError()); pm.addExtensionProvider("bad-payload", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadPayloadError()); pm.addExtensionProvider("bad-sessionid", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.BadSessionIDError()); pm.addExtensionProvider("session-expired", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider.SessionExpiredError()); } public boolean register(String account, String password) { Registration reg = new Registration(); reg.setType(IQ.Type.SET); reg.setTo(connection.getServiceName()); reg.setUsername(account);// 注意这里createAccount注册时,参数是username,不是jid,是“@”前面的部分。 reg.setPassword(password); reg.addAttribute("android", "geolo_createUser_android");// 这边addAttribute不能为空,否则出错。所以做个标志是android手机创建的吧!!!!! PacketFilter filter = new AndFilter(new PacketIDFilter( reg.getPacketID()), new PacketTypeFilter(IQ.class)); PacketCollector collector = connection.createPacketCollector(filter); connection.sendPacket(reg); IQ result = (IQ) collector.nextResult(SmackConfiguration .getPacketReplyTimeout()); if (result == null) { MLog.makeText("连接超时"); } else if (result.getType() == IQ.Type.RESULT) { MLog.makeText("注册成功"); return true; } else { MLog.makeText(result.getError().toString()); } return false; } public boolean login(String userName, String userPwd) { try { connection.login(userName, userPwd); user = userName + "@" + connection.getServiceName(); return true; } catch (Exception e) { e.printStackTrace(); } MLog.makeText("登录失败"); return false; } public void changePassword(String pwd) { try { connection.getAccountManager().changePassword(pwd); } catch (Exception e) { e.printStackTrace(); } } /** * 更改用户状态 */ public void setPresence(int code) { Presence presence = null; switch (code) { case 0: presence = new Presence(Presence.Type.available); connection.sendPacket(presence); MLog.makeText("设置在线"); break; case 1: presence = new Presence(Presence.Type.available); presence.setMode(Presence.Mode.chat); connection.sendPacket(presence); MLog.makeText("设置Q我吧"); break; case 2: presence = new Presence(Presence.Type.available); presence.setMode(Presence.Mode.dnd); connection.sendPacket(presence); MLog.makeText("设置忙碌"); break; case 3: presence = new Presence(Presence.Type.available); presence.setMode(Presence.Mode.away); connection.sendPacket(presence); MLog.makeText("设置离开"); break; case 4: Roster roster = connection.getRoster(); Collection<RosterEntry> entries = roster.getEntries(); for (RosterEntry entry : entries) { presence = new Presence(Presence.Type.unavailable); presence.setPacketID(Packet.ID_NOT_AVAILABLE); presence.setFrom(connection.getUser()); presence.setTo(entry.getUser()); connection.sendPacket(presence); } // 向同一用户的其他客户端发送隐身状态 presence = new Presence(Presence.Type.unavailable); presence.setPacketID(Packet.ID_NOT_AVAILABLE); presence.setFrom(connection.getUser()); presence.setTo(StringUtils.parseBareAddress(connection.getUser())); connection.sendPacket(presence); MLog.makeText("设置隐身"); break; case 5: presence = new Presence(Presence.Type.unavailable); connection.sendPacket(presence); MLog.makeText("设置离线"); break; default: break; } } public void logoutAccount() { try { connection.getAccountManager().deleteAccount(); } catch (Exception e) { e.printStackTrace(); } } public Collection<RosterGroup> getGroups() { return connection.getRoster().getGroups(); } public List<RosterEntry> getEntriesByGroup(String groupName) { List<RosterEntry> Entrieslist = new ArrayList<RosterEntry>(); RosterGroup rosterGroup = connection.getRoster().getGroup(groupName); Collection<RosterEntry> rosterEntry = rosterGroup.getEntries(); Iterator<RosterEntry> i = rosterEntry.iterator(); while (i.hasNext()) { Entrieslist.add(i.next()); } return Entrieslist; } public Drawable getUserImage(String user) { ByteArrayInputStream bais = null; try { VCard vcard = new VCard(); // 加入这句代码,解决No VCard for ProviderManager.getInstance().addIQProvider("vCard", "vcard-temp", new org.jivesoftware.smackx.provider.VCardProvider()); if (user == "" || user == null || user.trim().length() <= 0) { return null; } vcard.load(connection, user + "@" + connection.getServiceName()); if (vcard == null || vcard.getAvatar() == null) return null; bais = new ByteArrayInputStream(vcard.getAvatar()); BitmapDrawable drawable = new BitmapDrawable(bais); bais.close(); return drawable; } catch (Exception e) { e.printStackTrace(); } return null; } public List<RosterEntry> getAllEntries() { List<RosterEntry> Entrieslist = new ArrayList<RosterEntry>(); Collection<RosterEntry> rosterEntry = connection.getRoster() .getEntries(); Iterator<RosterEntry> i = rosterEntry.iterator(); while (i.hasNext()) { Entrieslist.add(i.next()); } return Entrieslist; } public boolean addGroup(String groupName) { try { connection.getRoster().createGroup(groupName); MLog.makeText("创建成功"); return true; } catch (Exception e) { e.printStackTrace(); } return false; } /** * 添加好友 无分组 * * @param userName * @param name * @return */ public boolean addUser(String userName, String name) { try { String account = userName + "@" + connection.getServiceName(); connection.getRoster().createEntry(account, name, null); return true; } catch (Exception e) { e.printStackTrace(); } return false; } public boolean addUserWithName(String userName, String name, Presence.Type type) { return addUserWithName(userName, name, XMsgConst.X_DEFAULT_GROUP, type); } /** * 添加好友 有分组 * * @param userName * @param name * @param groupName * @return */ public boolean addUserWithName(String userName, String name, String groupName, Presence.Type type) { try { Presence subscription = new Presence(type); subscription.setTo(userName); userName += "@" + connection.getServiceName(); connection.sendPacket(subscription); if (type == Type.subscribed) connection.getRoster().createEntry(userName, name, new String[] { groupName }); return true; } catch (Exception e) { e.printStackTrace(); return false; } } public boolean removeUser(String userName) { try { RosterEntry entry = null; if (userName.contains("@")) entry = connection.getRoster().getEntry(userName); else entry = connection.getRoster().getEntry( userName + "@" + connection.getServiceName()); if (entry == null) entry = connection.getRoster().getEntry(userName); connection.getRoster().removeEntry(entry); return true; } catch (Exception e) { e.printStackTrace(); } return false; } public List<XUserItem> searchUsers(String userName) { List<XUserItem> results = new ArrayList<XUserItem>(); try { UserSearchManager usm = new UserSearchManager(connection); String serverDomain = "search." + connection.getServiceName(); Form searchForm = usm.getSearchForm(serverDomain); Form answerForm = searchForm.createAnswerForm(); answerForm.setAnswer("Username", true); answerForm.setAnswer("search", userName); ReportedData data = usm.getSearchResults(answerForm, serverDomain); Iterator<Row> it = data.getRows(); Row row = null; XUserItem user = null; while (it.hasNext()) { row = it.next(); String uName = row.getValues("Username").next().toString(); String Name = row.getValues("Name").next().toString(); String Email = row.getValues("Email").next().toString(); user = new XUserItem(uName, Name, Email); results.add(user); } return results; } catch (XMPPException e) { // TODO Auto-generated catch block e.printStackTrace(); } return results; } public void sendMessage(String toJID, String message) { // TODO Auto-generated method stub final Message newMessage = new Message(toJID, Message.Type.chat); newMessage.setBody(message); connection.sendPacket(newMessage); } @Override public void connectionClosed() { // TODO Auto-generated method stub MLog.makeText("连接已关闭"); } @Override public void connectionClosedOnError(Exception arg0) { // TODO Auto-generated method stub MLog.makeText("连接关闭异常"); arg0.printStackTrace(); } @Override public void reconnectingIn(int arg0) { // TODO Auto-generated method stub MLog.makeText("reconnectingIn:" + arg0); } @Override public void reconnectionFailed(Exception arg0) { // TODO Auto-generated method stub MLog.makeText("连接失败"); arg0.printStackTrace(); } @Override public void reconnectionSuccessful() { // TODO Auto-generated method stub MLog.makeText("重连成功"); } @Override public void connectionCreated(Connection arg0) { // TODO Auto-generated method stub BroadSender.sendBroadcast(SplashActivity.class); } @Override public void processPacket(Packet packet) { // TODO Auto-generated method stub if (packet instanceof Message) { Message msg = (Message) packet; CacheUtils.getInstance().addMessage(msg); BroadSender.sendBroadcast(ChatActivity.class, "action", XMsgConst.X_PACKET_TYPE_MESSAGE); } else if (packet instanceof Presence) { Presence presence = (Presence) packet; String from = presence.getFrom();// 发送方 String to = presence.getTo();// 接收方 Type type = presence.getType(); int typeValue = 0; if (type.equals(Presence.Type.subscribe)) { // 好友申请 typeValue = XMsgConst.X_PRESENCE_SUBSCRIBE; } else if (type.equals(Presence.Type.subscribed)) { // 同意添加好友 typeValue = XMsgConst.X_PRESENCE_SUBSCRIBED; } else if (type.equals(Presence.Type.unsubscribe)) { // 拒绝添加好友 typeValue = XMsgConst.X_PRESENCE_UNSUBSCRIBE; } else if (type.equals(Presence.Type.unsubscribed)) { // 删除好友 typeValue = XMsgConst.X_PRESENCE_UNSUBSCRIBED; } else if (type.equals(Presence.Type.unavailable)) { // 好友下线 typeValue = XMsgConst.X_PRESENCE_UNAVAILABLE; from = processFrom(from); CacheUtils.getInstance().putPresence(from, presence); } else { // 好友上线 typeValue = XMsgConst.X_PRESENCE_ONLINE; from = processFrom(from); CacheUtils.getInstance().putPresence(from, presence); } String[] params = new String[] { "action", XMsgConst.X_PACKET_TYPE_PRESENCE, "type", String.valueOf(typeValue), "from", from, "to", to }; BroadSender.sendBroadcast(MainActivity.class, params); } } /** * 去掉多余的服务器字符串 * * @param from * @return */ private String processFrom(String from) { int endPos = from.lastIndexOf("/"); if (endPos != -1) from = from.substring(0, endPos); return from; } }
收藏的用户(0) X
正在加载信息~
推荐阅读
最新回复 (25)
- QQA9DA9BFAC8F2D2548E41486E035CBC 2015-1-7引用 2楼太需要了,找了半天!终于找到最新可用的了!
- anofapaqaciqo 2015-3-6引用 3楼喜欢
-
-
-
- SINA1988289085 2015-11-11引用 7楼是这个里面,这个里面有分类你没看到么?
if (packet instanceof Message)
这句就表示是消息数据,然后放到缓存队列里面。else if (packet instanceof Presence)
这个才是状态消息! - rabbitly520 2015-11-11引用 8楼不好意思哥,我瞎了。。。。
- ucefisehubex 2015-11-11引用 9楼哥,在问一个,这个msg就是他发过来的信息吗?,还有,他的user怎么获取
- RamiroAngas609 2015-11-11引用 10楼是的,消息。你还是仔细看下源码的。源码我编译可以成功运行的。 然后也很简单的几个类。一会儿就能看完了。
- ihahulaxoyuk 2015-12-3引用 11楼楼主你好,我这个openfire为什么接收消息的时候进入不了if (packet instanceof Message) {这个判断里面而是进入 else if (packet instanceof Presence) {这个请求判断里面,跪求,真的很急!
-
-
- Hector44C8666249 2016-11-25引用 14楼开始连接服务器失败。、。
- aimsky0411 2016-11-26引用 15楼为什么在手机运行不行?
- QQ5A6F14981E49E18D62D676BE28B416 2016-12-4引用 16楼电脑和手机处于同一个局域网就行了,ip地址为你电脑本机无限局域网ip地址,不要弄错。
-
-
-
-
-
-
-
- usiqogimev 2017-4-5引用 24楼楼主大哥,为什么我一直停留在初始化界面,一直在连接服务器进不去呢?看到求回复谢谢
- QQ6C7A11BD6560DE7B2981B6ACC54D7F 2017-4-5引用 25楼我的服务端已经关了,你自己搭建一个服务端吧!
-
站点信息
- 文章2305
- 用户1336
- 访客11455538
每日一句
Talent without working hard is nothing.
没有努力,天份不代表什么。
没有努力,天份不代表什么。
MySQL 数据库优化
This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its de
免ROOT实现模拟点击任意位置
Mobaxterm终端神器
CreateProcessW要注意的细节问题
Autonomous NAT Traversal
【教程】win10 彻底卸载edge浏览器
eclipse工程基于Xposed的一个简单Hook
排名前5的开源在线机器学习
Mac OS最简单及(Karabiner)快捷键设置
发一款C++编写的麻将
VMware NAT端口映射外网访问虚拟机linux
独家发布最新可用My-AutoPost——wordpress 采集器
新会员