【0】README
1)本文旨在 给出源代码 实现 smack client + openfire server 实现 peer to peer communication
2)当然,代码中用到的 user 和 pass, 你需要事先在 openfire 里面注册;
3)also , you can checkout the source code from
https://github.com/pacosonTang/core-java-volume/tree/master/coreJavaSupplement/smack-client ;
Attention)要区分 ChatManagerListener and ChatMessageListener, 这两个监听器,它们的功能是不同的,但是长相却十分相似;
【2】代码如下
package com.xmpp.client;import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Set;import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.chat.Chat;
import org.jivesoftware.smack.chat.ChatManager;
import org.jivesoftware.smack.chat.ChatMessageListener;
import org.jivesoftware.smack.packet.ExtensionElement;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Message.Body;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smackx.delay.packet.DelayInformation;// this class encapsulates some info for
// connection, login, creating chat.
public class UserChatBase { // smakc client base class.private XMPPTCPConnectionConfiguration conf;private AbstractXMPPConnection connection;private ChatManager chatManager;private Chat chat;/*** @param args refers to an array with ordered values as follows: user, password, host, port.*/public UserChatBase(String... args) {String username = args[0];String password = args[1];conf = XMPPTCPConnectionConfiguration.builder().setUsernameAndPassword(username, password).setServiceName(MyConstants.HOST).setHost(MyConstants.HOST).setPort(Integer.valueOf(MyConstants.PORT)).setSecurityMode(SecurityMode.disabled) // (attention of this line about SSL authentication.).build();connection = new XMPPTCPConnection(conf);chatManager = ChatManager.getInstanceFor(connection);// differentiation ChatManagerListener from ChatMessageListenerchatManager.addChatListener(new MyChatListener(this));}/*** connect to and login in openfire server.* @throws XMPPException * @throws IOException * @throws SmackException */public void connectAndLogin() throws SmackException, IOException, XMPPException {System.out.println("executing connectAndLogin method.");System.out.println("connection = " + connection);connection.connect();System.out.println("successfully connection.");connection.login(); // client logins into openfire server.System.out.println("successfully login.");}/*** disconnect to and logout from openfire server.* @throws XMPPException * @throws IOException * @throws SmackException */public void disconnect() {System.out.println("executing disconnect method.");try {connection.disconnect();} catch (Exception e) {e.printStackTrace();}}/*** create chat instance using ChatManager.*/public Chat createChat(String toUser) { toUser += "@" + MyConstants.HOST;chat = chatManager.createChat(toUser); // create the chat with specified user.(startup a thread)MessageHandler handler = new MessageHandler(chat); MessageHandler.Sender sender = handler.new Sender(); // creating inner class.new Thread(sender).start();// creating thread over.return chat;}/*** get chat timestamp, also time recoded when the msg starts to send.* @param msg * @return timestamp.*/public String getChatTimestamp(Message msg) {ExtensionElement delay = DelayInformation.from(msg);if(delay == null) {return null;}Date date = ((DelayInformation) delay).getStamp();DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);return format.format(date);}public XMPPTCPConnectionConfiguration getConf() {return conf;}public AbstractXMPPConnection getConnection() {return connection;}public ChatManager getChatManager() {return chatManager;}public Chat getChat() {return chat;}
}
package com.xmpp.client;import java.util.Locale;public class ClientA { // one client public static void main(String a[]) throws Exception {Locale.setDefault(Locale.CHINA);UserChatBase client = new UserChatBase(new String[]{"tangtang", "tangtang"});client.connectAndLogin();System.out.println("building connection between tangtang as sender and pacoson as receiver.");// create the chat with specified user.(startup a thread)client.createChat("pacoson");}
}
package com.xmpp.client;import java.util.Locale;public class ClientB { // another client.public static void main(String a[]) throws Exception {Locale.setDefault(Locale.CHINA);UserChatBase client = new UserChatBase(new String[]{"pacoson", "pacoson"});client.connectAndLogin();System.out.println("building connection between pacoson as sender and tangtang as receiver.");// create the chat with specified user.(startup a thread)client.createChat("tangtang");}
}
package com.xmpp.client;import java.util.Set;import org.jivesoftware.smack.chat.Chat;
import org.jivesoftware.smack.chat.ChatManagerListener;
import org.jivesoftware.smack.chat.ChatMessageListener;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Message.Body;// 监听器
public class MyChatListener implements ChatManagerListener{private UserChatBase client;public MyChatListener(UserChatBase client) {this.client = client;}@Overridepublic void chatCreated(Chat chat, boolean createdLocally) {if (!createdLocally) {chat.addMessageListener(new ChatMessageListener() {@Overridepublic void processMessage(Chat chat, Message message) {String from = message.getFrom();Set<Body> bodies = message.getBodies();String timestamp = client.getChatTimestamp(message);if(timestamp != null) {System.out.println(timestamp);}for(Body b : bodies) {System.out.println(from + ":" + b.getMessage());}}});}}
}
package com.xmpp.client;public class MyConstants { // 常量类public static final int PORT = 5222;public static final String HOST = "lenovo-pc";public static final String PLUGIN_PRESENT_URL= "http://lenovo-pc:9090/plugins/presence/status?";//= "http://lenovo-pc:9090/plugins/presence/status?jid=pacoson@lenovo-pc&type=text&req_jid=tangtang@lenovo-pc";public static final String buildPresenceURL(String from, String to, String type) {return PLUGIN_PRESENT_URL + "jid=" + to + "@" + HOST + "&"+ "req_jid=" + from + "@" + HOST + "&"+ "type=" + type;}
}
package com.xmpp.client;import java.util.Scanner;import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.chat.Chat;// 创建发送msg 线程.
public class MessageHandler {private Chat chat;public MessageHandler(Chat chat) {this.chat = chat;}class Sender implements Runnable{/*public Sender(Chat chat) {MessageHandler.this.chat = chat;}*/public Sender() {}@Overridepublic void run() {Scanner scanner = new Scanner(System.in);while(scanner.hasNext()) {String line = scanner.nextLine();try {chat.sendMessage(line);} catch (NotConnectedException e) {e.printStackTrace();break;}}} }class Receiver {}
}
(干货——只有当 消息接收者处于离线的时候,其接收到的消息才会封装 delay 元素,其属性有 stamp 记录了 msg 发送的时间。(also, you can refer to https://community.igniterealtime.org/thread/22791))
