用JAVA建立稳定的多线程服务器_百度文库_第1页
用JAVA建立稳定的多线程服务器_百度文库_第2页
用JAVA建立稳定的多线程服务器_百度文库_第3页
用JAVA建立稳定的多线程服务器_百度文库_第4页
用JAVA建立稳定的多线程服务器_百度文库_第5页
已阅读5页,还剩1页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、内容: 消息系统的建立 服务器的结构 端口监听线程类PORTListenThread 单个客户端在连接池中的映像类ClientSingle 分组转发的实现类Group 主服务器类Server 总结 关于作者 侯光敏 (wearebug 2002 年 7 月 本文详细的介绍了使用Java语言建立一套多线程服务器的过程,该服务器使用对象传递消息,在线程中使用队列机制,使服务器的性能大大提高了。这套服务器可以被用于各种C/S或B/S结构的应用程序中。 Java语言是完全面向对象的,它的线程机制和对象序列化特别容易使用,使用Java来建立一套多线程服务器要比使用其它语言方便的多,如果你再把它的异常处理

2、机制利用好,那么你就可以建立一个商业级的多线程服务器了。由于采用了消息队列和Socket传输方式,所以不会出现丢消息的问题。这套服务器可以作为实时聊天服务器、多人协同的协作服务器等等。 消息系统的建立 这套服务器的消息系统采用的是对象传输的机制,而不是以前常常使用的字符串传输。采用对象传输的好处是扩展方便,如需要建立一个新的消息只需要从一个统一的基类继承下来,然后再写自己实现的方法就行了。这样也符合面向对象领域里一条重要的原则:OCP(open_closed Principle,即一个好的设计应该能够容纳新的功能的增加,但是增加的方式不是修改原有的类,而是添加新的类。 首先建立一个基类:Msg

3、,该抽象类中有两个域sender和receiver分别纪录消息的发送者和接收者。这两个域是在构造消息类时就填写的,receiver域可以为空,空表示发给谁都可以,由转发服务器来决定。该类的方法包括取得这两个域的值和消息的处理函数。消息的处理函数process(是空函数,供继承者重载。 建立了这个抽象基类后,你就可以继承它完成你自己的类。举个例子,假如我要建立一个分组协同工作的绘图系统,而且支持组员之间的对话,那么我可以建立如下的类集合: SendTextMsg(String sender,String receiver,String info/向指定的人发送对话。 AddLineMsg(Str

4、ing sender,Point a,Point b/在指定的点之间绘制一条直线 AddRectangle(String sender,point start,Point end/建立指定的矩形 AddRotundaMsg(String sender,Point center,int radius/建立指定的圆 RemoveObjectMsg(String sender,int ID/删除指定编号的图形对象 以此类推,可以建立很多的消息类。在每个类的内部都由一个处理该类的方法process(,填写该方法就可以实现对消息类的处理,而服务器只负责完成消息的转发功能。这样,一套消息系统就建立了。 服

5、务器的结构 如果要服务器实现同时为每个客户端服务,就要使用多线程,建立一个线程池,当有客户端连接时就在池中开辟一个线程为它服务。同样,要避免大量消息到达时处理不过来而导致丢失的情况,就要使用消息队列。这个服务器是分层的处理的。 类关系图如下所示: 服务器的工作过程是这样的,建立了一个Server类作为主类,它含有程序的入口函数main(。在构造函数中初始化一个数组存放ClientSingle类,它其实就是单独处理一个连接用户的类。然后启动一个线程PORTListenThread,该线程的作用就是监听端口上有没有人登陆,当有人连接时交给Server的addClient(处理。Server的add

6、Client(方法会在刚才那个数组中建立一个ClientSingle对象,然后把剩下的事都交给它做。 端口监听线程类PORTListenThread 该线程类在run(函数的开始部分首先要检查serverScoket是否为空,保证循环开始时不要出错。然后进入一个死循环的监听: while(true /死循环监 trySocket clientSocket=null; clientSocket=serverSocket.accept(; server.addClient(clientSocket;/转交Server处理 catch (IOException eSystem.out.println

7、("监听端口时出错"+e;/显示错误 单个客户端在连接池中的映像类ClientSingle 每一个客户端连接到服务器后,服务器会自动在连接池中建立该客户端的一个映像,所有的操作都交给这个映像去具体执行,所以ClientSingle中一定要包含客户端的一些基本的信息。比如客户端的名称、登陆时间等等。在该类中有两个消息队列sendQueue(发送队列)和receiveQueue(接收队列)缓存消息。 ClientSingle类是继承自Thread的,它还是一个调用者。在初始化的时候启动两个子线程类SingleSender和SingleListener运行。SingleSende

8、r负责监听指令发送队列中有没有指令,有则发送;SingleListener负责监听有没有消息到达,有则把这些消息加入到接收队列中去,由ClientSingle处理。所以ClientSingle的主要任务就是对这两个队列的处理。这两个队列可以用Vector实现,非常地简单。 /-将消息加入发送队列中- synchronized void send(Object o sendQueue.add(o; 为了稳定控制子线程的运行,并不鼓励在run(方法的死循环标志都用true,而是使用了一个布尔型的变量finish。外部可以通过把这个标志置为假而停止线程的运行。 发送子线程类启动后执行run(中的循环

9、(以finish为结束标志),在该循环内首先判断ClientSingle中的发送队列是否为空,为空时睡眠一定的时间再重新判断,这也是一个while循环。不为空则开始处理队列中的消息,把它取出后放入输出流中发送。 public void run( while (!father.finish /循环监听 while(father.v.isEmpty( /当发送队列为空的时候线程睡眠500毫秒 tryThread.sleep(500; catch(InterruptedException eSystem.out.println(e; if (!father.v.isEmpty( /发送队列不为空时

10、try Object a=father.v.firstElement(;/取出队列中的第一个消息 father.v.removeElementAt(0;/从队列中删除 oos.writeObject(a;/发送该消息 oos.flush(; catch(IOException e displayMessage(" 传输失败 !" father.finish=false; 接收子线程SingleListener类和发送子线程是类似的,它们的run(方法都差不多。不同的是接收子线程把收到的消息加入到ClientSingle的接收队列中去,由它处理。 ClientSingle类的

11、run(方法就在循环地读取接收队列receiveQueue中的内容,为空时等待;不为空时依次取出处理和转发。处理消息的函数是processMsg(),它只是执行消息类自己的process(方法罢了。在处理完后,会调用Server类的方法进行各种类型的转发。 分组转发的实现类Group 为了实现对客户端分组,我建立了Group类。在这个类中有一个列表存放已经存在于连接池中的那些ClientSingle类的引址。只要遍历整个列表就能访问所有组中的成员。这个列表可以用Vector实现,也可以用哈希表,我推荐后者,主要是为了能够按名字存取。 组对象本身也是可以存在Server类的组列表中的。 分组功能

12、对多人的协同系统来说是非常重要的,特别是分组对某一个共享空间操作的时候。就以上面的协同绘图系统为例,如果10个人里有三个人要另起炉灶,那么他们三个的画板就不能让其他人看到,这就必须有"组"个划分。 主服务器类Server Server类是最核心的类,它在这个框架中起到调度全局的作用,上面介绍的那些类都由它来统一的构造和调用。 Server类的域包括一个定长的数组存放ClientSingle实例,它就是连接池的实现。还要有一个哈希表存放Group实例。Server类的方法都是对这两个类的操作。 建立ClientSingle数组的目的是保证服务器的稳定性。其实,你也可以选择不建

13、立它,只是动态地构造对象,但是那样不好管理连接的用户,而且由于各种操作系统对进程的处理不同,动态建立服务线程会很不稳定。所以我先建立一个数组作为这些对象的容器,在开始时就估计好连接者的最大数量。Server类的addClient(函数: void addClient(Socket socket int c=0; trywhile (schc!=null C+;/搜索数组中的空余空间 catch(ArrayIndexOutOfBoundsException e try socket.close(;/出现异常关闭槽连接 catch(IOException ee System.out.println("数组溢出" return; schc=new ClientSingle(c,socket,father,this;/在搜索到的位置建立ClientSingle对象 Server类中转发的方法有:sendToAll()、sendToOne()、sendToGroup()等等。这些方法都是对线程池中的方法的操作,比较简单,不外乎都是

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论