admin 管理员组

文章数量: 1184232


2024年3月29日发(作者:linux培训靠谱么)

维普资讯

第18卷第2期 

辽宁税务高等专科学校学报 

2006年4月 

Vo1.18,No.2 

LlAONING TAXATlON COLLEGE JOURNAL 

Apr..2006 

用Java语言建立多线程服务器 

洪运国 

(大连职业技术学院 信息技术系,辽宁大连116035) 

摘要:介绍了使用Java语言建立多线程服务器的过程,该服务器使用对象传递消息,在线程中使用队列 

机制,使服务器的性能大大提高了。这套服务器可以被用于各种c/s或B/S结构的应用程序中。 

关键词:类;消息系统;服务器;多线程 

中围分类号;TP312 文献标识鹂:A 文章编号:1008—2859(2006)02—0065—02 

1.引言 

建立指定的矩形 

Java语言是完全面向对象的,它的线程机制和对象序列 

AddRotundaMsg(String sender,Point center.int 

化特别容易使用,使用Java来建立一套多线程服务器要比使 

radius)//建立指定的圆 

用其它语言方便的多,如果你再把它的异常处理机制利用 RemoveObjectMsg(String sender,int ID)//删除指定 

好,那么你就可以建立一个商业级的多线程服务器了。由于 

编号的图形对象 

采用了消息队列和Socket传输方式,所以不会出现丢消息的 

问胚。这套服务器可以作为实时聊天服务器、多人协同的协 

以此类推,可以建立很多的消息类。在每个类的内部都 

作服务器等等。 

由一个处理该类的方法process()。填写该方法就可以实现 

2.消息系统的建立 

对消息类的处理,而服务器只负责完成消息的转发功能。这 

这套服务器的消息系统采用的是对象传输的机制。而不 样,一套消息系统就建立了。 

是以前常常使用的字符串传输。采用对象传输的好处是扩展 

3.服务器的结构 

方便,如需要建立一个新的消息只需要从一个统一的基类继 

如果要服务器实现同时为每个客户端服务,就要使用多 

承下来,然后再写自己实现的方法就行了。这样也符合面向 

线程.建立一个线程池.当有客户端连接时就在池中开辟一 

对象领域里一条重要的原则:OCP(open--closed Principle), 

个线程为它服务。同样,要避免大量消息到达时处理不过来 

即一个好的设计应该能够容纳新的功能的增加,但是增加的 

而导致丢失的情况,就要使用消息队列。这个服务器是分层 

方式不是修改原有的类,而是添加新的类。 

的处理的。 

首先建立一个基类:Msg。该抽象类中有两个域sender 服务器的工作过程是这样的。建立了一个Server类作为 

和receiver分别纪录消息的发送者和接收者。这两个域是在 主类。它含有程序的入13函数main() 在构造函数中初始化 

构造消息类时就填写的,receiver域可以为空,空表示发给谁 

个数组存放ClientSingle类,它其实就是单独处理一个连 

都可以.由转发服务器来决定。该类的方法包括取得这两个 接用户的类。然后启动一个线程PORTListenThread,该线程 

域的值和消息的处理函数。消息的处理函数process()是空 的作用就是监听端13上有没有人登陆,当有人连接时交给 

函数,供继承者重载。 

Server的addClient()处理。Server的addClient()方法会在刚 

建立了这个抽象基类后,你就可以继承它完成你自己的 

才那个数组中建立一个ClientSingle对象,然后把剩下的事 

类。举个例子,假如我要建立一个分组协同工作的绘图系统, 都交给它做 

而且支持组员之间的对话,那么我可以建立如下的类集合; 

4.单个客户端在连接池中的映像类 

SendTextMsg(String sender,String receiver,String 

每一个客户端连接到服务器后,服务器会自动在连接池 

info)//向指定的人发送对话。 

中建立该客户端的一个映像,所有的操作都交给这个映像去 

AddLineMsg(String sender,Point a,Point b)//在指 

具体执行,所以ClientSingle中一定要包含客户端的一些基 

定的点之间绘制一条直线 

本的信息。比如客户端的名称、登陆时间等等。在该类中有两 

AddRectangle(String sender,point start,Point end)// 

个消息队列sendQueue(发送队列)和 receiveQueue(接收队 

收稿日期;2005—09—20 

作者简介:洪运国(1970一).男.辽宁大连人.讲师。 

维普资讯

66・ 辽宁税务高等专科学校学报 第18卷 

列)缓存消息。 

ClientSingle类是继承自Thread的。它还是一个调用 

者 在初始化的时候启动两个于线程类SingleSender和 

SingleListener运行。SingleSender负责监听指令发送队列中 

有没有指令.有则发送;SingleListener负责监听有没有消息 

到达,有则把这些消息加入到接收队列中去,由ClientSingle 

处理。所以ClientSingle的主要任务就是对这两个队列的处 

理。这两个队列可以用Vector实现。非常地简单。 

//——-将消息加入发送队列中… 

synchronized void send(Object 0) 

{ 

sendQueue.add(o); 

) 

为了稳定控制子线程的运行,并不鼓励在run()方法的 

死循环标志都用true,而是使用了一个布尔型的变量finish。 

外部可以通过把这个标志置为假而停止线程的运行。 

发送子线程类启动后执行run()中的循环(以finish为结 

束标志),在该循环内首先判断ClientSingle中的发送队列是 

否为空,为空时睡眠一定的时间再重新判断.这也是一个 

while循环。不为空则开始处理队列中的消息,把它取出后放 

人输出流中发送。 

接收子线程SingleListener类和发送子线程是类似的, 

它们的run()方法都差不多 不同的是接收子线程把收到的 

消息加入到ClientSingle的接收队列中去,由它处理。 

ClientSingle类的run()方法就在循环地读取接收队列 

receiveQueue中的内容,为空时等待;不为空时依次取出处 

理和转发。处理消息的函数是processMsg(),它只是执行消 

息类自己的process()方法罢了。在处理完后,会调用Server 

类的方法进行各种类型的转发。 

5.分组转发的实现类 

为了实现对客户端分组,我建立了Group类。在这个类 

中有一个列表存放已经存在于连接池中的那些ClientSingle 

类的引址。只要遍历整个列表就能访问所有组中的成员。这 

个列表可以用Vector实现,也可以用哈希表,我推荐后者, 

主要是为了能够按名字存取。 

组对象本身也是可以存在Server类的组列表中的。 

分组功能对多人的协同系统来说是非常重要的,特别是 

分组对某一个共享空间操作的时候 就以上面的协同绘图系 

统为例,如果10个人里有三个人要另起炉灶,那么他们三个 

的画板就不能让其他人看到,这就必须有“组”个划分。 

6.主服务器类 

Server类是最核心的类,它在这个框架中起到调度全局 

的作用,上面介绍的那些类都由它来统一的构造和调用。 

Server类的域包括一个定长的数组存放ClientSingie实 

例,它就是连接池的实现。还要有一个哈希表存放Group实 

例。Server类的方法都是对这两个类的操作。 

建立ClientSingle数组的目的是保证服务器的稳定性。 

其实。你也可以选择不建立它,只是动态地构造对象,但是那 

样不好管理连接的用户,而且由于各种操作系统对进程的处 

理不同,动态建立服务线程会很不稳定。所以我先建立一个 

数组作为这些对象的容器,在开始时就估计好连接者的最大 

数量。Server类的addClient()函数: 

void addClient(Socket socket) 

{ 

int C=0; 

try{while(sch[c]1=nul1)c++;)//搜索数组中的空 

余空问 

catch(ArraylndexOutOfBoundsExeeption e)f 

try{socket.close();}//出现异常关闭槽连接 

catch(IOException ee){System.out.println(“数组溢 

出”);) 

return; 

) 

sch[c]=new ClientSingle(c。socket.father,this);//在 

搜索到的位置建立ClientSingle对象 

) 

Server类中转发的方法有: 

sendToAll()、sendToOne()、sendToGroup()等等 这些 

方法都是对线程池中的方法的操作,比较简单,不外乎都是 

找到线程池中的某个ClientSingle对象,然后调用它的send 

()方法罢了 

注意,这些转发的方法可能被很多子线程同时调用.所 

以为了保持线程的稳定,千万记住要在方l法前加 

synchronized关键字。 

7.总结 

通过上面的描述你可以发现.要建立稳定的服务器程 

序,消息队列和线程池是很重要的。此外,也要考虑到很多的 

意外情况的发生。一般的程序员在写完线程的run()方法的 

循环后就不管了,其实还应该考虑跳出循环后的资源释放等 

等问题。 

参考文献: 

El3结城浩.Java多线程设计模式[M].北京:中国铁道出版社, 

2005. 

[23张立科.Java网络高级编程FM].北京:人民邮电出版社.2001. 

[31叶至军,由浅入深--Java 2自学教程[M].北京;人民邮电出版 

社,2001. 

[4]耿样义.Java2实用教程[M].北京:清华大学出版社+2001, 

[5]阎非.java程序设汁教程[M].北京;中国水利水电出版社, 

2O04. 


本文标签: 消息 服务器 线程