Jive Messenger 源码研究

Jive Messenger 源码研究
第一部分 Jabber Server工作原理和流程
1)Server的启动
通过下面图片来做一个简单的了解
1.       Launcher(GUI) Jive Messenger Server 启动和停止的可视化界面 ,
按下 Start Server 开始启动
:[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) 客户端连接 , 待续
 
2 Client Server 交互流程

1   客户端启动一个 XMPPConnection Server 建立 Socket 的连接
2   用户通过 PacketWriter IQ Server ,服务器 ClientSocketReader 接受到这个 IQ ,对用户登陆进行认证
3   ClientA Packet ClientB ClientSocketReader 会调用 PacketRouter Packet 转发给 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 ,创建一个 SocketConnection SocketReader ,并启动 SocketReader 线程
4   SocketReader 会创建一个用户会话( Session
 
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
在信号处理领域,DOA(Direction of Arrival)估计是一项关键技术,主要用于确定多个信号源到达接收阵列的方向。本文将详细探讨三种ESPRIT(Estimation of Signal Parameters via Rotational Invariance Techniques)算法在DOA估计中的实现,以及它们在MATLAB环境中的具体应用。 ESPRIT算法是由Paul Kailath等人于1986年提出的,其核心思想是利用阵列数据的旋转不变性来估计信号源的角度。这种算法相比传统的 MUSIC(Multiple Signal Classification)算法具有较低的计算复杂度,且无需进行特征值分解,因此在实际应用中颇具优势。 1. 普通ESPRIT算法 普通ESPRIT算法分为两个主要步骤:构造等效旋转不变系统和估计角度。通过空间平移(如延时)构建两个子阵列,使得它们之间的关系具有旋转不变性。然后,通过对子阵列数据进行最小二乘拟合,可以得到信号源的角频率估计,进一步转换为DOA估计。 2. 常规ESPRIT算法实现 在描述中提到的`common_esprit_method1.m`和`common_esprit_method2.m`是两种不同的普通ESPRIT算法实现。它们可能在实现细节上略有差异,比如选择子阵列的方式、参数估计的策略等。MATLAB代码通常会包含预处理步骤(如数据归一化)、子阵列构造、旋转不变性矩阵的建立、最小二乘估计等部分。通过运行这两个文件,可以比较它们在估计精度和计算效率上的异同。 3. TLS_ESPRIT算法 TLS(Total Least Squares)ESPRIT是对普通ESPRIT的优化,它考虑了数据噪声的影响,提高了估计的稳健性。在TLS_ESPRIT算法中,不假设数据噪声是高斯白噪声,而是采用总最小二乘准则来拟合数据。这使得算法在噪声环境下表现更优。`TLS_esprit.m`文件应该包含了TLS_ESPRIT算法的完整实现,包括TLS估计的步骤和旋转不变性矩阵的改进处理。 在实际应用中,选择合适的ESPRIT变体取决于系统条件,例如噪声水平、信号质量以及计算资源。通过MATLAB实现,研究者和工程师可以方便地比较不同算法的效果,并根据需要进行调整和优化。同时,这些代码也为教学和学习DOA估计提供了一个直观的平台,有助于深入理解ESPRIT算法的工作原理。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值