- 浏览: 348060 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
pacoson:
感谢楼主。请受小生一拜。
ANT预编译JSP -
zhuhongming123:
一楼的同学Lucene4.* 以上的 已经改成了Numeric ...
Lucene日期排序及组合查询 -
ywjk520:
RangeQuery在哪个包里?
Lucene日期排序及组合查询 -
willwen:
有个疑问,楼主,为何初始化bits 从txt读取已有的网址是直 ...
布隆过滤器(Bloom Filter)之java实例 -
yu_226528:
还不如没有呢
jFreeChart 在jsp页上实现简单的折线图、柱状图
IM概念和Jabber协议
从现在开始,我们将建立一个基础的程序,在以后的章节都要使用。我们将开始开发一个基本地jabber服务。以此为基础,我们在以后章节增强它的功能。
3.1一个基本的Jabber服务
如果你曾经写过服务类程序,一个基本的Jabber服务的代码设计对你来说是非常熟悉的。即使没有,也不用担心。服务类程序从根本来说是非常简单的。最大的困难和复杂度在于附加的一些特征,作为一个大规模的服务器,需要安全有效的应付多用户并发的情况。
本书中设计的Jabber服务是一个简单的可靠的以及遵循jabber协议。简单是为了我们更容易的理解和修改,因为我们感兴趣的地方以及的目的是学习典型服务器的重要特征。一旦我们明白了这些基本特征,修改和扩展是非常容易。
一个简单的jabber服务需要做三件事:
l 连接到客户端
l 读取jabber xml流
l 对客户端的输入作出反应
令人不可思议的是,我们实现这些事情只需要寥寥几个java类就可以实现。在这一节,我们建立一个基本的jabber服务实现这三个任务。
3.1.1我们的目标
在开始之前,设置一个明确的目标是非常有帮助的。目标指导我们设计和实施的准则。在系统中,我们会用到以下准则:
简单——要求事情简单纯粹是从美学观点来看的。另外,简单的软件意味着更加可靠,容易理解和易于修改。后面的两个准则是在此基础上的。保持事物的简单性,我们将会有一个好的开端。
服从标准——我们开发一个Jabber服务的目的是明白和阐明jabber协议。很明晰,我们不想为了正确的实现而失去教育的意义。现在最合适的效果是介于这之间的。
容易理解——代码必须是容易理解的。一个混乱的难以理解的代码是很难说明问题和解释他们。我们要实现的是倾斜的代码。
便于修改——虽然代码是用来学习的。你可能更加希望他用在真实世界中,在许多时候,你根据你的需要修改。我们将尽量使它易于修改,无论面对什么情况。
同时也要明确我们的软件暂时不会做的事情:安全性,伸缩性,可管理性,有效性行和运行速度。一个一般快的机器就可以应付20个人的网络系统,足够中小部门的使用。
3.1.2我们的服务代码
我们的代码将接受和处理来自客户端的连接,解析xml流,依照jabber命令发出xml流。软件的启动被严格的限制,但是当我们附加新的jabber协议支持,扩展了服务特性和功能。
有意思的是我们可以使得我们的软件实现jabber的高级功能。在第十章,他们包含了服务器安全的实现,在现有系统中嵌入jabber功能,集成其他企业资源。
3.1.3基本的服务设计
我的jabber服务被分开为三个基本模块:
Session Pool:一个jabber客户服务器会话集合。每一个会话管理一个人java.net.Socket连接和SessionID和jabberID等元数据。
XML解析:xml解析类处理输入的jabber xml数据,把他们转变成java 包对象。Xml解析类依赖于简单xmlAPI(SAX)解析。
Packet处理:服务器对输入的Packet作出反应。在多数情况下,服务简单的将Packet路由到特定的输入终端。然而许多Packet必须经过处理,生成一个或多个回复Packet。
把所有的Packet对象集合到packetQueue进行处理,
PacketQueue:这个类是关于Packet对象的基本队列集合结构。PacketQueue参与到Packet处理模块对Packet对象的xml解析以及存储Packet对象到PacketQueue中。Packet处理把Packets对象一处队列并处理它们。PacketQueue的设计是线程安全的,允许单独的服务器线程同步处理packetQueue。
Jabber Packets——Packets类存储的信息数据包包含了jabber服务器与客户端互发JabberXml数据包。
当客户端连接到服务器,基本的服务操作开始。Server将为此连接建立一个会话对象,并开始解析进入的xml。Xml解析后转变成packet对象被推入到packet队列。一个packet处理的集合把packet从队列中取出,处理它们并产生输出的packet,使用session索引找到正确的session对象的xml输出流,并且输出xml到流中。
session池,xml解析,和packet队列在一起互相协助处理jabber packet。我们将在packet处理类中实现多个协议。现在我们提供了最基本的输入packet路由。我们遍历jabber协议知道将添加更多的packet处理。
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写信息到SessionSocket的outputStream中,或者Java.io.Reader读取信息。通过创建和保存一个Reader和Werter,使用者可以不用得到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定位Sessions。SessionIndex类承担这些职责。
3.2.3SessionIndex类提供session查找
SessionIndex的主要职责是更具jabberID查找Session对象。对服务器来说按照jabberID定位到正确的Session对象是很重要的,因为多数的jabber包来自于jabber用户。服务器必须根据收到的jabberID定位到适当的session并回复包到客户端。
为实现这些功能,SessonIndex类包括两个Java.util.HashTable对象:userIndex和JidIndex。UserIndex Hashtable提供了Session的用户和Session对象的映射。JidIndex提供了Session的jabberID字符串和Session对象之间的映射。
使用SessonIndex引导session的查找使用以下算法:
l 检查如果接收者的jabber id是在jidindex 。比较使用
精确匹配允许客户发送信息到其他特定客户。
l 如果没有,查看jabberId的用户名在userIndex中
l 如果没有找到,返回null。
使用这个算法服务器能够显示一个合理的消息回路。例如,假设一个客户端的jabberID是iain@shigeoka.com/home,连接服务器。SessionIndex将查找JabberID,在jidIndex中找到它,返回合适的Session。现在,假设消息的地址是iain@shigeoka.com。SessinIndex类在JIdIndex中查找,但没有找到。然而当SessionIndex在userIndex中查找,找到iain,返回连接iain@shigeoka.com/home的Session。
最后,考虑一下消息地址iain@shigeoka/work。SessionIndex类在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中为每一个用户名使用了一个Sessions的LinkedList,messages遵循着先到先服务的原则。换句话说,如果你连接以下客户端:
一个发送到iain@shigeoka.com的消息将别发送到iain@shigeoka.com/home。如果iain@shigeoka.com/home没有连接,那么消息发送到iain@shigeoka.com给iain@shigeoka.com/work。这些不是标准的jabber路由动作,但是是在第8章之前,在我们添加用户帐户,用户出席和支持协议之前,能做到得到最好的状态。当我们在这里使用用户出席支持,我们将能够实现更加老道的,优先的路由元数据按照指定的jabber标准。使用SessionIndex的关键是包处理类关联的QueueThread类。
3.3xml解析子系统
XML解析是jabber服务所做的最复杂的任务了,然而,对于java的Coder们来说,这个任务显然是小儿科,因为我们用完善的Java Sax解析库来做这些工作。我们仅仅需要对查找出处理这些的方法。
服务器的XML解析类的任务就是将xml流信息写入Packet对象,存储的PacketQueue。我们用packet和packetQueue类开始我们的xml解析过程
3.3.1描述Jabber包
jabber协议包含了客户端与服务器端交换xml碎片的办法。我们把这些xml碎片作为一个包来提交。我们把这些信息包装到java对象中,他们工作使用起来要比xml字符串简单的多。使用java对象还可以享受到java的类型检测,继承以及多态等特征的好处。
预览jabber协议就可以知道它有三个核心包需要操心:
<message></message>
,<presence></presence>
<iq></iq>
另外需要我们注意的是打开的和关闭的流标签以及流错误包:
<stream:stream>
<stream:error></stream:error>
</stream:stream>
支持这些包和标签从根本上说是很简单的。在本章最后,我们的jabber服务将能够识别和控制他们。第一步是识别他们的一般特征和封装他们到java类。
Jabber包其实是一个xml片段,因此可以把它当成一个mini的xml文档。在java中又很多的方法处理xml文档。最流行的依据w3cdom标准。大部分的javaxml解析库包含标准的支持w3cdom的java类。在dom中,xml文档时类似于树的结构体。
我们需要的xml表示不是如dom标准所能胜任的。我们知道我们接受各种各样的xml文档和我们指明的java对象。另外,不使用dom也可使我们的代码避免依附到dom库和建立服务器所需的代码。最后,我们的包类必须做比呈现xml片段更多的功能。Packets类必须能充当如下两个角色:
Pack Store——packets类是一个主要的数据储存类。信息能够被标准的java方法调用。我们能够存储包到类似w3cdom的树形数据结构。
XML writer——packet类能够知道到怎么创建自己的xml字符串表示方式。这个特征允许其他类从xml字符串呈现对象转换成的packet对象。
一个单独的xml解析类在本章最后将从接受的xml字符串转变成packet对象。Packet类的数据结构反映了xml片段的结构。例如,考虑如下xml包:
<message to='recipient'>
<subject>hello</subject>
<body>How are you doing?</body>
</message>
我们可以把它们组织到三个包中:
Packet: message (attribute to='recipient)
Packet: subject
String (value "hello")
Packet: body
String (value "How are you doing?");
在这样的数据结构中,我们能够看到一个包有一个元素名,零个或多个属性名值对,零个或多个子节。一个packet的子对象是一个字符串或其packet对象。另外,每个包有一个相关的命名空间。
作为一个java类,我们能够存储packet的子节到java.util.List类型的List中。他的属性在java.util.Hashtable,并且其他值是字符串。如果这个包没有父节点,包的parent值是null。
这个类包括三个构造器:
The Packet class constructors
public class Packet {
public Packet(String element){
setElement(element);
}
public Packet(String element, String value){
setElement(element);
children.add(value);
}
public Packet(Packet parent,
String element,
String namespace,
Attributes atts){
setElement(element);
setNamespace(namespace);
setParent(parent);
//Copy attributes into hashtable
for (int i = 0; i < atts.getLength(); i++){
attributes.put(atts.getQName(i), atts.getValue(i));
}
}
parent和children成员变来那个负责packet的树形结构和他们的子节。我们能够用LinkedList类型的类存储packet和Strings。另外,packet的命名空间和元素名必须被存储成字符串。
String namespace;
public void setNamespace(String name) { namespace = name; }
public String getNamespace() { return namespace; }
String element;
public void setElement(String element) { this.element = element; }
public String getElement() { return element; }
Packet parent;
public Packet getParent() { return parent; }
public void setParent(Packet parent){
this.parent = parent;
if (parent != null){
parent.children.add(this);
}
}
LinkedList children = new LinkedList();
public LinkedList getChildren() {return children;}
packet提供了几个构造器。假设我们用个如下的xml包:
<item>
ItemValue
<sub-item>sub-item value</sub-item>
<sub-item>another value</sub-item>
</item>
有三个典型的典型任务,其他的类将在packet中执行:
l 获取给定元素名的子包。(例如:<sub-item>sub-item value</sub-item>).
l 获取packet的第一个字符串值。
l 获取字符串值相关的第一个子包。
第一个方法是从一个给定的元素名定位第一个子包。他在getFirstChild()中实现。例如,考虑最近的<itme>xml包。你能够在itme包对象中调用getFirstChild(“sub-itme”),得到元素名为sub-item的子包。
public Packet getFirstChild(String subelement){
Iterator childIterator = children.iterator();
while (childIterator.hasNext()){
Object child = childIterator.next();
if (child instanceof Packet){
Packet childPacket = (Packet)child;
if (childPacket.getElement().equals(subelement)) {
return childPacket;
}
}
}
return null;
}
另外一些基本的任务是依据一个元素获得字符串值。例如,我们得到了<sub-item>子包,我们能够知道他的值(“sub-item value”)。你能够通过调用<sub-item>的包对象getValue()方法得到。
public String getValue(){
StringBuffer value = new StringBuffer();
Iterator childIterator = children.iterator();
while (childIterator.hasNext()){
Object valueChild = childIterator.next();
if (valueChild instanceof String){
value.append((String)valueChild);
}
}
return value.toString().trim();
}
甚至有许多类似的情况,当我们想知道sub-packet的子节的字符串值。再上一个例子中,我们通过调用子包的getFirstChild(“sub-item”),得到<sub-item>的子包值。然后调用getValue()得到他的字符串值。有了这些方便的方法,我们能够更方便的结合到getChildValue()方法中。public String getChildValue(String subelement){
Packet child = getFirstChild(subelement);
if (child == null){
return null;
}
return child.getValue();
}
输入包经常依赖于会话上下文和其它动作路由。每一个在我们的jabber服务中的client或server能够有一个相关的session对象出处session上下文。这个packet存储这个会话对象的引用。
Session session;
public void setSession(Session session) { this.session = session; }
public Session getSession() {
if (session != null){
return session;
}
if (parent != null){
return parent.getSession();
}
return null;
}
许多jabber协议依赖于packet属性翻译包相关信息和他的动作。Packet类存储属性到java.util.Hashtable。另外,他提供了几个方便的方法访问大部分的一般packet属性:
l to——包的接受对象
l from——包发送者
l id——包ID,唯一标识包
l type——包类型。依据协议而定。
Hashtable attributes = new Hashtable();
public String getAttribute(String attribute) {
return (String)attributes.get(attribute);
}
public void setAttribute(String attribute, String value) {
if (value == null){
removeAttribute(attribute);
} else {
attributes.put(attribute,value);
}
}
public void removeAttribute(String attribute){
attributes.remove(attribute);
}
public void clearAttributes(){
attributes.clear();
}
public String getTo() { return (String)attributes.get("to"); }
public void setTo(String recipient) { setAttribute("to",recipient); }
public String getFrom() { return (String)attributes.get("from"); }
public void setFrom(String sender){ setAttribute("from",sender); }
public String getType() { return (String)attributes.get("type"); }
public void setType(String type){ setAttribute("type",type); }
public String getID() { return (String)attributes.get("id"); }
public void setID(String ID) { setAttribute("id",ID); }
}
最后,packet类能够把它自己写成一个xml字符串,依靠java.io.Writer。创建xml呈现的过程包括遍历树顺序,输出合适的元素,属性,以及子节。
public void writeXML() throws IOException {
writeXML(session.getWriter());
}
public void writeXML(Writer out) throws IOException{
out.write("<");
out.write(element);
//Output the attributes for the element
Enumeration keys = attributes.keys();
while (keys.hasMoreElements()){
String key = (String)keys.nextElement();
out.write(" ");
out.write(key);
out.write("='");
out.write((String)attributes.get(key));
out.write("'");
}
//Empty element
if (children.size() == 0){
out.write("/>");
out.flush();
return;
}
out.write(">");
//Iterate over each child
Iterator childIterator = children.iterator();
while (childIterator.hasNext()){
Object child = childIterator.next();
//Send value to Writer
if (child instanceof String){
out.write((String)child);
//Or recursively write its children's XML
} else {
((Packet)child).writeXML(out);
}
}
out.write("</");
out.write(element);
out.write(">");
out.flush();
}
public String toString(){
try {
StringWriter reply = new StringWriter();
writeXML(reply);
return reply.toString();
} catch (Exception ex){
}
return "<" + element + ">";
}
}
packet置入,接受来源,一个单独的服务端包队列。
3.3.2 服务的焦点,packetQueue类
packetQueue类是一个受限的响应集合的基本数据结构类。然而,他是服务器端的信息流的焦点。Packet从客户端聚集到packetQueue。然后packet按照packet的元素名发散出去。许多操作方法能够被服务器激活,并且同步到packetQueue。
Comand操作设计模式:
For those familiar with design patterns, our packet handling system is a minor
variation on the Command Processor design pattern.9
“The Command Processor design pattern separates the request for a service
from its execution. A command processor component manages requests as
separate objects, schedules their execution, and provides additional services
such as the storing of request objects for later undo.
的jabber服务中,xml解析充当命令控制器的作用,接受请求和转换
在我们的jabber服务,XML解析动作作为command控制器接受请求,转换xml流到命令。QueeueThread充当命令处理机获得paceket并调度他们的执行。不管像不像命令处理模式,packets是不会自己处理他们自己的运行。双重功能的命令处理供应者和命令处理代替我们的packet处理类,提供我们的整个的包处理功能。
使用comandprocessor模式的好处是:
l 请求触发的可扩展性——支持选择启动的方法是的能够很容易的桥连我们的jabber服务和其它message系统。
l 请求的操作和数量上的可扩展性——快速改变jabber协议是非常重要的。
l 相关服务的可编程——在特殊情况下,我们只要稍稍修改QueueThread就能够容易的记录packets和重放jabber会话。
l 应用的可测试性——QueueThread是一个极好的接入点,为我们测试xml解析和packet处理。一旦开启,记录和重放session是一个巨大的帮助。
l 并发——包和他们的处理是一个相对分离的计算。当线程同时执行时,QueueThread能够容易的分配处理。
Commander processor模式有一些缺陷:
l 效率的损耗——转换数据格式和提供中间处理步骤需要而外的计算时间的存储空间。
l 潜在着过多的命令类——大部分时候,我们避免把所有的包表现为单一的,一般的paceket类。我们为简单性而降低了一半的呈现效率。另外,一个packet类能够呈现不定数量的packet类。我们的服务必须建立额为的逻辑来垂腭这些包。
PacketQueue必须:
l 存储包——接受packet对象推入packetQueue的底
l 回收包——允许packet对象退出packetQueue,并移除它
l 线程安全——无障碍的允许多线程同步从packetQueeue 中push和pull packet。
l 提供线程同步——如果PacketQueue是空的,调整pull包之前让调用者停止一会儿直到一个新的packet进入队列,或者线程终止。线程能够同步的使用它们的操作和保存服务资源。
操作packet对象的线程能够有效的不断的从packetqueue拉出packet对象。PacketQueue自己必须确保这些工作的线程只能够在packetQueue正常有效的情况下执行。
packetQueeue的对象是非常简单的。一个java.util.LinkedList对象,用来存储Packets和一点用来支持服务器多线程环境的基本要素。
在下面高亮的部分提示了方法push()和pull()是线程安全保护的。每一个push()方法的调用时引起了notifyAll()唤醒等待的pull()处理线程。Pull()方法的定时器在队列是空的时候调用wait()方法。
public class PacketQueue {
//Actual storage is handled by a java.util.LinkedList
LinkedList queue = new LinkedList();
public synchronized void push(Packet packet){
queue.add(packet);
notifyAll();
}
public synchronized Packet pull(){
try {
while (queue.isEmpty()) {
wait();
}
} catch (InterruptedException e){
return null;
}
return (Packet)queue.remove(0);
}
}
loop是必须的,因为push()方法调用notifyAll(),唤醒所有等待的pull()。如果仅仅一个packet被推进队列,第一个线程执行移除从队列中。所有其他等待的线程继续运行,队列是空的,他们定时wait(),直到下一个包的到来。
如果你不能理解java线程代码,你可以信任这些工作,写一些测试验证一下,或者学习关于java线程的知识。我已经尽力将本书的中关于thread的代码最小化,但是服务代码倾向于沉重的线程。如果你希望学习到线程,有几个很好的书可以看。另外,java在线文档也提供免费指导。
现在,我们看看用jabberInputHandle类处理xml解析。
3.3.5java中的 SAX 解析(略)
3.4包处理和服务器线程
我最终需要的jabber服务器,包括服务包处理类和服务器端线程。包处理是继承自PacketListerer接口的简单对象,处理包对象。我们用的包处理类实现我们知道的jabber协议。
在这一章,我们将创建三个packet处理类:
l 当未关闭的<stream:stream>发送时一个OpenStreamhandler类为每一个连接创建Sessiong对象。
l 一个简单的messagehandler类,实现Jabber包路由初始版本。
l 当发送关闭标签<stream:stream>时候,CloseStreamhandler类经关闭连接。
服务的线程系统有三个类组成,每一个类代表一个线程执行:
l Server——主应用程序类和主执行线程。这个类创建jabber服务socket和接受新的jabber客户连接。
l ProcessTread——服务器线程类接受连接处理。他创建一个jabberInputHandler和一个输入xml流过程。ProcessThread线程处理和连接一一相对。
l QueueThread——这个线程类从PacketQueeue得到包然后他打发给适当的包处理类。在jabber服务中仅仅有一个活动的queueThread对象。
在同一时间有许多线程在服务上执行,然而,只有三种类型的需要你的关心,并且只有ProcessThread有超过一个的实例在执行。理解服务工作的最后办法,看看3.6图,显示了服务器上都发生了什么。
我们看看服务的主应用首先启动。他的首要任务是创建QueueThread类。新的queueThread立即调用pull()接受PacketQueue的包。QueueThread定时是因为队列中没有包。服务然后等待这用java.net.ServerSocekt.accept()调用连接。
在服务器上一个客户连接。这促使服务器创建一个processThread。这个ProcessTrhead用saX解析开启解析输入xml流和我们的JabberInputhandler类。当客户端发送xml包到服务器,ProcessTrhead的解析类创建包对象并调用push()加入到PacketQueue。
队列中新的Packet唤醒QueueThread。QueeuThread确定包已经被推入队列,然后用当前处理类处理它。包处理发送输出xml包到客户端。
注意仅有一个服务线程接受连接,并且一个QueueThread处理从packetQueue的包对象。然而,每一个客户链接有一个活动的processThread。有共享执行线程的方法处理输入的客户连接。另外,服务器有许多的包处理线程。然而,在我们的服务中,我们使他们尽量的简单。
从服务的主类创建QueueThread和ProcessThread,我们首先看到有两个帮助线程类,在运行服务助力额之前。QueueThread是个更加的复杂,我们就在这开始。
发表评论
-
基于 XMPP协议的即时消息服务端简单实现
2010-01-27 11:43 1038服务器端XmppSeverConnection类事件 / ... -
基于XMPP协议的即时通讯工具的服务器端实现
2010-01-27 11:15 1453基于XMPP协议的即时通讯 ... -
基于 XMPP协议的服务器端 文件互传的简单实现
2010-01-27 11:11 1817学习一下基于XMPP协议的文件传输,首先假设用户已经登录, ... -
Instant Messaging java(1)
2010-01-27 10:12 9701.Jabber包怎么路由 理解Jabber路由计划的关键是 ... -
Jabber核心协议(XMPP Core :RFC3920)
2010-01-27 09:32 19111、 /XML StanzaXML StreamStream ... -
Jabber 协议 概述(2)
2010-01-27 09:30 11766.19. jabber:x:encrypted——加密消息 ... -
Jabber 协议 概述(1)
2010-01-27 09:21 12111. 介绍 Jabber是一个由开源社区发起并领导开发的 ...
相关推荐
This book describes how to create Instant Messaging applications in Java and covers the Jabber IM protocols. If you want to create new IM systems, integrate them with your existing software, or wish ...
即时通讯(Instant Messaging,简称IM)是现代网络通信的重要组成部分,Java 作为广泛使用的编程语言,为开发此类应用提供了强大的支持。"Instant Messaging in Java" 针对使用 Java 进行即时通讯系统开发进行了深入...
描述:“Java IM协议”阐述了Java环境下即时消息(Instant Messaging,简称IM)系统的开发与实现,特别是聚焦于Jabber协议,这是一种基于XML的即时通讯协议,广泛应用于企业级通信系统和个人聊天软件中。 标签:...
根据提供的文件信息,本文将详细解析“Java中的即时通讯(Instant Messaging in Java)”这一主题。主要内容包括:即时通讯的基本概念、Jabber协议的介绍及其在Java中的应用。 ### 即时通讯基本概念 即时通讯...
Manning - Instant Messaging in Java - The Jabber Protocols及书中源代码。 介绍jabber(xmpp)协议以及用java编写即时通讯(im)软件的好书,深入浅出。
即时通讯(Instant Messaging,简称IM)是现代网络通信的重要组成部分,它允许用户实时地进行文本、语音甚至视频交流。Java作为广泛使用的编程语言,有着丰富的库和框架支持IM系统的开发。本主题主要探讨的是基于...
该压缩包是使用java写的仿QQ服务端与客户端的即时通讯系统,内附建数据库的sql文件及测试时使用的数据,以及使用说明文件,本源码仅供java初学者在参考,其中有不足或一些其他没有测到的bug欢迎各位学习者给予及时...
《即时通讯技术在Java中的应用》是一本专为Java开发者准备的深度解析即时通讯(Instant Messaging,简称IM)系统的书籍。这本书由Manning出版社出版,深入探讨了如何利用Java技术构建高效、可靠的实时通信平台。Java...
2. **XMPP(Extensible Messaging and Presence Protocol)**:Jabber协议后来演变为XMPP,这是IETF批准的即时通讯和在线状态协议。书中会详细讲解XMPP的核心概念,如JID(Jabber ID)、XML流管理和认证机制。 3. *...
nstant messaging apps like Whatsapp, Kik Messenger, and Snapchat are hot right now and there are some existing instant messaging protocols that could be used to build your own Delphi XE6 Firemonkey ...
Lotus.Instant.Messaging.and.Web.Conferencing.Java.Toolkit.v6.5.1-ACMELotus公司的即时通讯和网络会议软件(Lotus Instant Messaging and Web Conferencing)的前身是Lotus Sametime,多年以来在商用IM领域中一直...
本指南主要关注如何使用ActiveMQ开发消息应用,通过`Instant Apache ActiveMQ Messaging Application Development How-to源码`,我们可以深入理解ActiveMQ的核心特性和实际应用。 1. **ActiveMQ简介**: - **概念*...
Yahha即时通讯是一款基于Java技术的开源即时消息客户端。这款软件的设计理念旨在提供一个可定制、可扩展的通信平台,让用户能够自由地进行信息交换,同时也为开发者提供了丰富的开发工具和接口,以支持二次开发和...
Underground IM是免费的Java Instant Messaging解决方案。 客户端和服务器均可用。 Underground IM是根据GNU通用公共许可证的条款免费分发的开源软件。 *公共服务器:64.94.101.216:5632
Java即时通讯(Instant Messaging,IM)系统是一种允许用户实时交流的应用程序,广泛应用于社交网络、企业内部通信等领域。本资料包“Java-Instant-Messaging.zip”包含了一个完整的Java编程实现的即时通讯系统的...
即时通讯(Instant Messaging,IM)程序是一种允许用户实时交流的应用,通常包括文本、语音、视频等多种通信方式。在本文中,我们将深入探讨如何使用Java语言分两部分构建一个IM程序:服务器端和客户端。 首先,...
Underground IM 是一个免费的 Java Instant Messaging 解决方案。 客户端和服务器都可用。 Underground IM 是根据 GNU 通用公共许可证条款免费分发的开源软件。 *公共服务器:64.94.101.216:5632
Java即时通信(Instant Messaging,IM)是网络应用中不可或缺的一部分,尤其在企业级通信和协作环境中。本项目“java-instant-communication.rar_平台”旨在提供一个基于Java平台的即时通信解决方案,涵盖服务器端和...
标题 "instantmessage" 提供的信息表明,这是一个关于即时通讯(Instant Messaging)的项目,可能是一个在线用户管理系统,具有实时聊天功能。使用了Java作为主要开发语言,并且涉及到DWR(Direct Web Remoting)...
Java 网络编程有着广泛的应用,例如:instant messaging、online banking、online shopping 等。Java 网络编程可以使得程序之间的通信变得更加方便、快捷和可靠。 本实验报告对Java 网络编程的基本概念和实现方法...