Jive Messenger 源碼研究

 Jive Messenger 源碼研究
第一部分 Jabber Server工作原理和流程
1)Server的啓動
通過下面圖片來做一個簡單的瞭解
1.       Launcher(GUI)Jive Messenger Server啓動和停止的可視化界面,
按下StartServer開始啓動
:[org.jivesoftware.messenger.launcher.Launcher]調用ServerStarter.start()
2.       [org.jivesoftware.messenger.starter.ServerStarter]加載lib庫文件,同時啓動一個
[org.jivesoftware.messenger.XMPPServer]實體

Class containerClass = loader.loadClass("org.jivesoftware.messenger.XMPPServer");
containerClass.newInstance();
 
3.       XMPPServer加載模塊(Modules),組件(Component),插件(Plugin)

public void start() {
        try {
            initialize();
 
            // If the server has already been setup then we can start all the server's modules
            if (!setupMode) {
                verifyDataSource();
                // First load all the modules so that modules may access other modules while
                // being initialized
                loadModules();
                // Initize all the modules
                initModules();
                // Start all the modules
                startModules();
            }
           // Load plugins. First, initialize component manager.
            InternalComponentManager.getInstance().start();
            File pluginDir = new File(messengerHome, "plugins");
            pluginManager = new PluginManager(pluginDir);
            pluginManager.start();
            …….
        }
        catch (Exception e) {
            …..
            shutdownServer();
        }
    }
 
下面我們來看一下服務器加載了那些Module(Component,Plugin也是非常重要的我將在以後的文章中做討論)

private void loadModules() {
        // Load boot modules
        loadModule(RoutingTableImpl.class.getName());
        loadModule(AuditManagerImpl.class.getName());
        loadModule(RosterManager.class.getName());
        loadModule(PrivateStorage.class.getName());
        // Load core modules
        loadModule(PresenceManagerImpl.class.getName());
        loadModule(SessionManager.class.getName());
        loadModule(PacketRouter.class.getName());
        loadModule(IQRouter.class.getName());
        loadModule(MessageRouter.class.getName());
        loadModule(PresenceRouter.class.getName());
        loadModule(PacketTransporterImpl.class.getName());
        loadModule(PacketDelivererImpl.class.getName());
        loadModule(TransportHandler.class.getName());
        loadModule(OfflineMessageStrategy.class.getName());
        loadModule(OfflineMessageStore.class.getName());
        // Load standard modules
        loadModule(IQAuthHandler.class.getName());
        loadModule(IQPrivateHandler.class.getName());
        loadModule(IQRegisterHandler.class.getName());
        loadModule(IQRosterHandler.class.getName());
        loadModule(IQTimeHandler.class.getName());
        loadModule(IQvCardHandler.class.getName());
        loadModule(IQVersionHandler.class.getName());
        loadModule(IQLastActivityHandler.class.getName());
        loadModule(PresenceSubscribeHandler.class.getName());
        loadModule(PresenceUpdateHandler.class.getName());
        loadModule(IQDiscoInfoHandler.class.getName());
        loadModule(IQDiscoItemsHandler.class.getName());
        loadModule(IQOfflineMessagesHandler.class.getName());
        loadModule(MultiUserChatServerImpl.class.getName());
        loadModule(MulticastDNSService.class.getName());
        // Load this module always last since we don't want to start listening for clients
        // before the rest of the modules have been started
        loadModule(ConnectionManagerImpl.class.getName());
    }
Server啓動的時候加載的模塊非常多,其中最後一個加載的ConnectionManagerImpl它是ConnectionManager接口的實現,用來負責管理用戶(jabberClient)連接
 
另外所有模塊都是繼承(extends)BasicModule或者實現(implements)Module
4. ConnectionManageImpl啓動

 public void start() {
        super.start();
        isStarted = true;
        serverName = server.getServerInfo().getName();
        createSocket();
        SocketSendingTracker.getInstance().start();
    }
Start方法創建Socket(監聽客戶端的連接),並啓動一個SocketSendingTracker線程,用來檢查Socket是否正常連接
5.JabberServer啓動完成
2)客戶端連接,待續
 
2ClientServer交互流程

1  客戶端啓動一個XMPPConnectionServer建立Socket的連接
2  用戶通過PacketWriterIQServer,服務器ClientSocketReader接受到這個IQ,對用戶登陸進行認證
3  ClientAPacketClientBClientSocketReader會調用PacketRouterPacket轉發給ClientB(現在先不太Server2Server的情況)
Jive Messenger Server如何創建Session(代碼分析)
 
 
ConnectionManagerImpl初始化(

//ConnectionManagerImpl.java
public void initialize(XMPPServer server) {
        super.initialize(server);
        this.server = server;
        router = server.getPacketRouter();
        deliverer = server.getPacketDeliverer();
        sessionManager = server.getSessionManager();
    }
ConnectionManagerImpl啓動

//ConnectionManagerImpl.java
public void start() {
        super.start();
        isStarted = true;
        serverName = server.getServerInfo().getName();
        createSocket();
        SocketSendingTracker.getInstance().start();
    }
ConnectionManagerImpl創建Socket

//ConnectionManagerImpl.java
private void createSocket() {
        ……
        // Start the port listener for s2s communication
        startServerListener(localIPAddress);
        // Start the port listener for external components
        startComponentListener(localIPAddress);
        // Start the port listener for clients
        startClientListeners(localIPAddress);
        // Start the port listener for secured clients
        startClientSSLListeners(localIPAddress);
    }
ConnectionManagerImpl開啓socket監聽,啓動SocketAcceptTread線程

//ConnectionManagerImpl.java
private void startClientListeners(String localIPAddress) {
            ……
            try {
                socketThread = new SocketAcceptThread(this, serverPort);
                ports.add(serverPort);
                socketThread.setDaemon(true);
                socketThread.start();
                ……
            }
            catch (Exception e) {
               …..
            }
        }
    }
SocketAcceptTread啓動過程

// SocketAcceptTread.java
public void run() {
        while (notTerminated) {
            try {
                Socket sock = serverSocket.accept();
                if (sock != null) {
                    Log.debug("Connect " + sock.toString());
                    connManager.addSocket(sock, false, serverPort);
                }
            }
            catch (IOException ie) {
              …..
                }
                     …..
        }
     // 線程結束的時候後面處理關閉serverSocket
     ……
    }
當一個Client連接到Server,ConnectionManagerImpl增加一個Socket連接

//ConnectionManagerImpl.java
public void addSocket(Socket sock, boolean isSecure, ServerPort serverPort) {
        try {
            SocketConnection conn = new SocketConnection(deliverer, sock, isSecure);
            SocketReader reader = null;
            String threadName = null;
            if (serverPort.isClientPort()) {
                reader = new ClientSocketReader(router, serverName,sock,conn);
                threadName = "Client SR";
            }
            else if (serverPort.isComponentPort()) {
                reader = new ComponentSocketReader(router, serverName, sock, conn);
                threadName = "Component SR";
            }
            else {
                reader = new ServerSocketReader(router, serverName, sock, conn);
                threadName = "Server SR";
            }
            Thread thread = new Thread(reader, threadName);
            thread.setDaemon(true);
            thread.start();
        }
        catch (IOException e) {
            Log.error(LocaleUtils.getLocalizedString("admin.error"), e);
        }
    }
ConnectionManagerImpl啓動一個SocketReader線程

//SocketReader.java
public void run() {
        try {
            reader = new XPPPacketReader();
            reader.setXPPFactory(factory);
            reader.getXPPParser().setInput(new InputStreamReader(socket.getInputStream(),
                    CHARSET));
            // Read in the opening tag and prepare for packet stream
            try {
                //socketReader啓動的時,需要創建一個Session來負責和Client的會話
                createSession();
            }
            catch (IOException e) {
                …..
            }
            // 會話結束後的處理
            if (session != null) {
                readStream();
            }
 
        }
        catch (EOFException eof) {
            // Normal disconnect
        }
      
    }
createSession() 調用abstract方法createSession(String namespace),這個方法的在不同客戶端的SocketReader中被實現,我們拿ClientSocketReader舉例

//ClientSocketReader.java
Boolean createSession(String namespace) …{
        if ("jabber:client".equals(namespace)) {
            // ClientSession負責創建一個ClientSession
            session = ClientSession.createSession(serverName, reader, connection);
            return true;
        }
        return false;
    }
 ClientSeesion創建ClientSeesion的過程

//ClientSeesion.java
public static Session createSession(String serverName, XPPPacketReader reader,
            SocketConnection connection)
throws XmlPullParserException, UnauthorizedException,IOException{
        ……
        // 爲用戶創建一個Session
        Session session = SessionManager.getInstance().createClientSession(connection);
        Writer writer = connection.getWriter();
        //創建packet response的開頭
        ……    
        boolean done = false;
        while (!done) {
            if (xpp.next() == XmlPullParser.START_TAG) {
                done = true;
                if (xpp.getName().equals("starttls") &&
                        xpp.getNamespace(xpp.getPrefix()).equals(TLS_NAMESPACE))
                {
                    writer.write("<proceed xmlns=/"urn:ietf:params:xml:ns:xmpp-tls/"/>");
                    if (isFlashClient) {
                        writer.write('/0');
                    }
                    writer.flush();
                    // TODO: setup SSLEngine and negotiate TLS.
                }
            }
        }
 
        return session;}
//SessionManager.java
public Session createClientSession(Connection conn) throws UnauthorizedException {
        if (serverName == null) {
            throw new UnauthorizedException("Server not initialized");
        }
        StreamID id = nextStreamID();
        ClientSession session = new ClientSession(serverName, conn, id);
        conn.init(session);
        // Register to receive close notification on this session so we can
        // remove and also send an unavailable presence if it wasn't
        // sent before
        conn.registerCloseListener(clientSessionListener, session);
 
        // Add to pre-authenticated sessions.
        preAuthenticatedSessions.put(session.getAddress().toString(), session);
        return session;
    }
 
總結一下:
1 ConnectionManagermentImpl初始化啓動
2 ConnectionManagermentImpl創建一個Socket啓動監聽
3  當客戶端啓動Socket連接, SocketAcceptThread接受客戶端連接
ConnectionManagerImpl調用addSocket,創建一個SocketConnectionSocketReader,並啓動SocketReader線程
4 SocketReader會創建一個用戶會話(Session
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章