第一部分 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("
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
)