Instant Messaging java(第三章)02

3.2会话池维持客户端连接

一个典型的jabber服务将维持许多并发的,长时间的客户端连接。每一个会话在客户端和服务器端定义一个上下文包,并在他们之间通行。每一Session的上下文都必须为维持每一个连接保持连接。它它包含了如下信息:

l       Session保持连接的jabberID

l       Session保持连接的StreamID

l       Session用到的java.net.Socket以及对应的java.io.Reader/Writer对象

l       Session状态(disconnected,connected,streaming,authenticated)

 

这个连接的集合和他的维持信息被封装在一个Session对象中。另外,所有的在服务器中的会话在包信息存取都是非常容易丢失的。我们开发一个集中的SessionIndex类就是为了保持我们的活动的会话不丢失以及保证通过jabberID能够找到会话。

我们首先看看Session类。

3.2.1会话类抽象一个连接

会话类提供了一个方便的session上下文信息分组的办法。类开始声明了两个构造器,基本的数据域和访问方法。我们也提供了两个为SessionSocket对象读写功能的方法。大部分时候,session对象用到java.io.Writer写信息到SessionSocketoutputStream中,或者Java.io.Reader读取信息。通过创建和保存一个ReaderWerter,使用者可以不用得到Socket,自己就可以得到Input/OutputStream,和创建Reader/writer

public class Session{

public Session(Socket socket) { setSocket(socket); }

public Session() { setStatus(DISCONNECTED); }

JabberID jid;

public JabberID getJID() { return jid; }

public void setJID(JabberID newID) { jid = newID; }

String sid;

public String getStreamID() { return sid; }

public void setStreamID(String streamID) { sid = streamID; }

Socket sock;

public Socket getSocket() { return sock; }

public void setSocket(Socket socket) {

sock = socket;

setStatus(CONNECTED);

}

Writer out;

public Writer getWriter() throws IOException {

if (out == null){

out = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));

}

return out;

}

Reader in;

public Reader getReader() throws IOException {

if (in == null){

in = new BufferedReader(new InputStreamReader(sock.getInputStream()));

}

return in;

}

最让人感兴趣的是session里的状态管理代码。通过几个类我们能够知道怎么在状态发生改变同时session状态发生改变。我们在下面的章节将会在客户端代码中真切的体会。为了支持这些功能,我们用的会话状态事件模型可以在Swing类中发现。

在此模型中,注册监听事件。当一个事件被触发,会话会通知注册的监听事件。这个过程一时间看来有些小混乱。但是其实这是一条康庄大道,是解决多个对象监控另外对象的变量的一个好办法。ListinListing 3.2 The Session class st atus event code

LinkedList statusListeners = new LinkedList();

public boolean addStatusListener(StatusListener listener){

return statusListeners.add(listener);

}

public boolean removeStatusListener(StatusListener listener){

return statusListeners.remove(listener);

}

public static final int DISCONNECTED = 1;

public static final int CONNECTED = 2;

public static final int STREAMING = 3;

public static final int AUTHENTICATED = 4;

int status;

public int getStatus() { return status; }

public synchronized void setStatus(int newStatus){

status = newStatus;

ListIterator iter = statusListeners.listIterator();

while (iter.hasNext()){

StatusListener listener = (StatusListener)iter.next();

listener.notify(status);

}

}

}

一个Java.util.LinkedList类用来维持一个Session监听列表。加入和删除一个状态是非常容易的。所有的状态时间监听必须继承StatusListener接口。

The StatusListener interface

public interface StatusListener {

public void notify(int status);

}

它只有一个notify()方法,被用在setStatus()方法发送一个事件信息给监听器。为了连贯性,我也为我设想的Session类的4个状态定义几个标准值。

会话类抽象了在客户端和服务器端的一个网络连接和jabberSesison。服务器将处理许多同步的Session,通一个组织结构为jabberID定位SessionsSessionIndex类承担这些职责。

3.2.3SessionIndex类提供session查找

SessionIndex的主要职责是更具jabberID查找Session对象。对服务器来说按照jabberID定位到正确的Session对象是很重要的,因为多数的jabber包来自于jabber用户。服务器必须根据收到的jabberID定位到适当的session并回复包到客户端。

为实现这些功能,SessonIndex类包括两个Java.util.HashTable对象:userIndexJidIndexUserIndex Hashtable提供了Session的用户和Session对象的映射。JidIndex提供了SessionjabberID字符串和Session对象之间的映射。

使用SessonIndex引导session的查找使用以下算法:

l       检查如果接收者的jabber id是在jidindex 。比较使用
精确匹配允许客户发送信息到其他特定客户。

l       如果没有,查看jabberId的用户名在userIndex

l       如果没有找到,返回null

使用这个算法服务器能够显示一个合理的消息回路。例如,假设一个客户端的jabberIDiain@shigeoka.com/home,连接服务器。SessionIndex将查找JabberID,在jidIndex中找到它,返回合适的Session。现在,假设消息的地址是iain@shigeoka.comSessinIndex类在JIdIndex中查找,但没有找到。然而当SessionIndexuserIndex中查找,找到iain返回连接iain@shigeoka.com/homeSession

 

最后,考虑一下消息地址iain@shigeoka/workSessionIndex类在jidIndex中查找失败,但是能够看到iain实体在userIndex并且返回Session附在iain@shigeoka.com/home。因此,消息被传到适当的用户但是是备用的资源。这个动作符合jabber消息路由规定。

执行的类可以简单明了的管理这些映射。

public class SessionIndex {

Hashtable userIndex = new Hashtable();

Hashtable jidIndex = new Hashtable();

public Session getSession(String jabberID){

return getSession(new JabberID(jabberID));

}

public Session getSession(JabberID jabberID){

String jidString = jabberID.toString();

Session session = (Session)jidIndex.get(jidString);

if (session == null){

LinkedList resources = (LinkedList)userIndex.get(jabberID.getUser());

if (resources == null){

return null;

}

session = (Session)resources.getFirst();

}

 

return session;

}

public void removeSession(Session session){

String jidString = session.getJID().toString();

String user = session.getJID().getUser();

if (jidIndex.containsKey(jidString)){

jidIndex.remove(jidString);

}

LinkedList resources = (LinkedList)userIndex.get(user);

if (resources == null){

return;

}

if (resources.size() <= 1){

userIndex.remove(user);

return;

}

resources.remove(session);

}

public void addSession(Session session){

jidIndex.put(session.getJID().toString(),session);

String user = session.getJID().getUser();

LinkedList resources = (LinkedList)userIndex.get(user);

if (resources == null){

resources = new LinkedList();

userIndex.put(user,resources);

}

resources.addLast(session);

}

}

如你所见,我在userIndex中为每一个用户名使用了一个SessionsLinkedListmessages遵循着先到先服务的原则。换句话说,如果你连接以下客户端:

iain@shigeoka.com/home

iain@shigeoka.com/work

iain@shigeoka.com/laptop

一个发送到iain@shigeoka.com的消息将别发送到iain@shigeoka.com/home如果iain@shigeoka.com/home没有连接那么消息发送到iain@shigeoka.comiain@shigeoka.com/work。这些不是标准的jabber路由动作,但是是在第8章之前,在我们添加用户帐户,用户出席和支持协议之前,能做到得到最好的状态。当我们在这里使用用户出席支持,我们将能够实现更加老道的,优先的路由元数据按照指定的jabber标准。使用SessionIndex的关键是包处理类关联的QueueThread类。

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值