用JAVA编制电子白板软件
----随着Internet的迅速发展,在Email、WWW、FTP等传统的非实时应用日趋成熟的同时,广大网络用户对在线实时交流的需求不断扩大,如网上会议、远程教学、协同工作等。这方面的应用软件也日益丰富起来。该类软件主要分为两类,一种是以目前BBS和主页上的聊天室为代表的纯文字型的交流工具;另一种就是本文要介绍的电子白板类交流工具。电子白板除了具备聊天室的全部功能外,更重要的是,它还引入了绘画图形交流功能,使网上交流的形象性和直观性大大加强了,弥补了文字交流的不足。当分布在Internet不同位置的用户用白板进行交流时,一个人在自己的白板上绘制的图形可以马上在别人的白板上显示出来,好象大家都在同一块白板上绘画,彼此间的距离感大大缩短了。
----目前具有电子白板功能的软件有微软的Netmeeting等。此类软件在使用前需要用安装盘安装(Netmeeting是InternetExplorer4.0的选装件),在设置完成后才能使用。相比而言,在主页中用JAVAApplet实现白板功能就显得优势很大。因为它不需要传统软件的下载、安装和设置的繁琐步骤,只要用支持JAVA的浏览器连接到该Applet所在主页,就可以使用白板。用于浏览器的普及性(大部分常用浏览器都支持JAVA,如InternetExploer3.0与NetscapeNavigator3.0及以上版本)使得这种电子白板的潜在客户群是巨大的。此外,用JAVA编制电子白板软件还有一个显而易见的优势,就是整个软件(尤其是白板服务器)无须重新修改编译就可在NT、Unix、Linux等支持JAVA的平台上运行。
----目前基于浏览器和JAVA的电子白板正处于起步阶段,笔者尚未在网上看到该类软件。由于工作需要,笔者自行开发了一套此类电子白板软件。这里想将开发中的一些经验介绍给大家,以达到共同交流的目的。
工作原理
----电子白板有两种实现模型,一种是无白板服务器,因此仅支持两个用户直接连结;另一种是有白板服务器,原则上不限制同时上线人数和交谈室个数,具体实现上可视服务器性能和需要而定。本文要介绍属于后者。
----当用户需用白板与他人交流时,需要先用浏览器连到Applet所在主页,Applet运行后会连接到该白板服务器,和服务器建立TCP连接。每个用户可以在自己的白板上(嵌在Applet画面中)绘制图形和输入文字,Applet会将这些信息通过已建立的网络连接发往白板服务器,并不断侦听、接收来自白板服务器的图形和文字信息,将其再现在用户的白板中。白板服务器的作用是不断侦听、接收来自各Applet的信息,并将其转发给其他用户。
----由于浏览器对JAVAApplet的限制,使得Applet只能访问发送该Applet的宿主主机,因此只能在该Applet所在主机上运行白板服务器,使得Applet能建立和远程白板服务器的联系。
功能设计
----一个实用的电子白板系统应该具备以下基本功能:
用户在浏览到白板主页时,需登录后才能进行交流。这将提供交流时用的名字,必要时还可做权限检查。
用户能够根据交谈室的交谈主题选择参加和退出现有的交谈室,并且能建立新的交谈室。可以根据该电子白板系统的应用领域和需要附加一些权限设置。
用户只能和在同一交谈室中的用户交流。一个交谈室的信息对于别的交谈室是不可见的。
白板应至少具有一些如更换画笔颜色、清除画板(仅影响自己的白板)等方便用户的功能。
白板应具有一个操作提示和操作信息反馈栏,对用户显示一些操作提示和操作结果信息,这样可以方便用户使用。
用户应能暂停和恢复自己的白板工作。
----为了增加白板的实用价值,可以考虑增加如与windows画笔工具类似的画正方形、圆形等类似功能。本例作为电子白板基本模型的建立,故没有加入这些功能。实际上,只要了解了下面要介绍的白板通讯协议集的设计原则,增加以上功能是非常容易的。
通讯协议集的制定
----由于JAVA内置的标准基础通讯协议是TCP/IP,所以我们只需在其基础上建立电子白板的应用层协议集。协议集的模型将采用服务器/客户机的请求/应答模式。可以根据需要实现的白板功能制定通讯协议集,协议集中包括登录、图形传输(分服务器发出和客户机发出两部分)、文字传输(分服务器发出和客户机发出两部分)、服务器要求刷新交谈室及成员名单、客户机要求刷新交谈室及成员名单、加入指定交谈室、退出交谈室、建立新交谈室、暂停/恢复交流等部分。
----由于已经依靠TCP/IP协议保证数据传输的正确性,所以在这个电子白板的通讯协议集的设计中应在保证功能的前提下尽量简洁,来提高带宽利用率。白板通讯协议集的细节可参考如下:
----注意:(S)表示该部分由服务器发出,客户机接收;
----(C)表示该部分由客户机发出,服务器接收;
----数据格式表示:引号之间表示字符串,(short)表示短整形数(2字节),(int)表示标准整形数(4字节)。
登录(C):"log"→用户名字符串。
图形传输(客户机发出)(C):"draw"→(int)颜色值→(short)直线起点横坐标→(short)直线起点纵坐标→(short)直线终点横坐标→(short)直线终点纵坐标。
图形传输(服务器发出)(S):"draw"→(int)颜色值→(short)直线起点横坐标→(short)直线起点纵坐标→(short)直线终点横坐标→(short)直线终点纵坐标。
文字传输(客户机发出)(C):"text"→用户在白板对话框中输入的文字字符串。
文字传输(服务器发出)(S):"text"→文字输入者姓名字符串→该用户输入的文字字符串。
服务器要求刷新交谈室及成员名单(S):"refresh"→交谈室1主题字符串→交谈室1中的用户1姓名字符串→交谈室1中的用户2姓名字符串→...→"complete"→交谈室2主题字符串→交谈室2中的用户1姓名字符串→交谈室2中的用户2姓名字符串→...→"complete"→...→最后一个交谈室主题字符串→最后一个交谈室中的用户1姓名字符串→最后一个交谈室中的用户2姓名字符串→...→"complete"→"ok"。
客户机要求刷新交谈室及成员名单(C):"refresh"。(服务器收到此命令,会执行前面的服务器要求刷新交谈室及成员名单子协议,以响应客户机请求)
加入指定交谈室(C):"join"→申请加入的交谈室主题字符串。
退出交谈室(C):"quit"。
建立新交谈室(C):"new"→申请建立的新交谈室主题字符串。(服务器收到此命令,会自动在该用户原来所在的交谈室中注销,并使该用户成为新交谈室的一员)
暂停交流(C):"pause"。
恢复交流(C):"continue"。
----以上为本电子白板软件所遵循的通讯协议集。这个协议集的可扩充性很强,可以随时按增加的功能扩充协议集。例如需要传送圆形图案,则可将如下协议加到协议集中:"circle"→(int)颜色值→(short)圆心横坐标→(short)圆心纵坐标→(short)圆半径。
编程实现
----程序设计分服务器JAVAApplication和客户端JAVAApplet两部分进行。
----编程中需要注意以下几点:
服务器程序不要采用客户端接入时建立用户线程,退出交谈室时销毁线程的工作流程。因为有些操作系统的线程操作机制不够健全,在线程销毁时线程所占资源不能被完全释放,以致于在白板服务器运行的过程中将逐渐消耗掉系统资源。所以应在服务器初始化时按照最大允许同时上线的用户数建立所有用户服务线程。这些线程将等待客户端接入,当用户退出交谈室时线程并不销毁,而是清除用户数据,重新进入等待接入状态,准备为下一个用户服务。这样就保证了白板服务器可以长期可靠运行。
当用户在白板上连续绘画时可能产生大量的图形数据,客户端Applet若在白板的AWT事件处理程序中完成将这些数据传输给服务器的任务,则很有可能由于网络I/O的瓶颈作用,使得AWT事件处理线程受阻,从而影响白板Applet、浏览器、其他正在运行的应用软件的界面相应性。解决的办法就是使Applet再建立一个后台绘图数据传输线程,白板的AWT事件处理程序将用户的绘图数据通过管道流(PipedStream)传输给这个线程后就返回,把网络传输的任务留给这个线程进行。
在服务器和客户端Applet中,协议集每一个子协议的实现都要分别建立一个同步块(synchronize),该子协议的全部操作都要在这个同步块内完成,以限制自由访问网络接插建立的输入流和输出流。使得当一个线程执行一个子协议时能够独占这些网络资源,而使别的线程不能访问这些资源,以保证线程能够完整正确地执行子协议。但是由于同步操作会降低线程调度和执行效率,所以要在确保子协议完整执行的前提下尽量缩小同步代码块的范围。
由于协议集中的数据类型既有字符串又有整形数,因此在程序中选用DataInputStream和DataOutputStream作为数据输入流和输出流。此外,由于UTF格式的文本支持中文字符集,且在字符串中已包含长度信息,可以方便数据读取,故在本程序的网络通信中的字符串全部采用UTF格式。设计自己的白板程序时,可以根据需要换用其他文本格式和编码规则,但一定要保证输入流和输出流采用的是同一种格式和编码。
考虑到目前NetscapeNavigator3.0和InternetExplorer3.0目前仍普遍使用,而这两种浏览器的JAVA虚拟机都不支持较新的JDK1.1标准,所以在本程序的客户机Applet部分中没有使用JDK1.1特有的类库。
----首先介绍服务器程序的编制。需确定主要的几个类及其成员函数。列表如下:
----ChatServer类:
----服务器程序的启动类。
----ChatServer():建立服务器管理界面。
----initServer():建立服务器插结,初始化交谈室数据,按照允许同时上线的最大用户数建立多个用户服务线程。
----go():启动用户服务线程。
----quit():中止用户服务线程,关闭服务器插结,并释放全部资源。
----User类:为Thread类的子类,实现用户服务线程,处理服务器/客户机会话。
----run():等待客户端接入;客户端接入后初始化网络资源,进入循环侦听客户端请求的状态,并根据客户端的请求调用相应的协议处理程序。
----sendText():按照文字传输子协议,接收用户发出的文字信息,并转发给同一交谈室的其他用户。
----sendDraw():按照图形传输子协议,接收用户发出的图形信息,并转发给同一交谈室的其他用户。
----commandCenter():为服务器接收到的指令选择运行适当的处理程序。
----server_ask_refresh():服务器主动刷新交谈室及成员名单。
----server_answer_reresh():响应客户机要求刷新交谈室及成员名单。
----server_answer_log():响应客户机登录。
----server_answer_join():响应用户加入指定交谈室请求。
----server_answer_pause():响应用户暂停交流请求。
----server_answer_continue():响应用户恢复交流请求。
----server_answer_newRoom():响应用户建立新交谈室请求。
----server_answer_quit():响应用户退出交谈室请求。
----server_ask_text():服务器向客户机转发文字信息。
----server_ask_draw():服务器向客户机转发图形信息。
----refreshToAll():服务器刷新所有在线客户端的交谈室数据。
----refreshToAllNotMe():服务器刷新除该用户外,所有在线客户端的交谈室数据。
----socketClose():用户申请退出时调用,关闭网络插结,释放线程占用的网络资源。
----RoomGroup类:保存所有交谈室数据,直接处理与交谈室有关操作。
----newRoom():建立新交谈室。
----join():加入指定交谈室。
----quit():退出指定交谈室。
----getUsersName():返回指定交谈室内的用户名。
----getRoomID():按照交谈室主题查询并返回交谈室ID号。
----Room类:保存并处理本交谈室用户数据。
----join():加入本交谈室。
----quit():退出本交谈室。
----getUsersName():返回本交谈室的用户名。
----DataBag类:包装图形和文字数据。
----AboutDialog类:生成About对话框,可显示版权信息。
----QuitDialog类:生成QuitDialog对话框,用于确认是否结束服务器运行。
----客户机Applet包含的类及其主要成员函数如下:
----ChatApplet类:为Applet类的子类,实现Runnable接口。
----是白板Applet的核心类,完成与用户交流和与服务器通讯的任务。
----init():初始化Applet用户界面。
----run()::循环侦听来自白板服务器的信息,调用commandCenter命令处理程序。
----start():生成并启动Applet线程。
----stop():中止Applet线程。
----destroy():中止后台图形数据传送线程,调用关闭网络资源函数。
----socketClose():关闭所有打开的网络插结和通讯流。
----openSocket():建立网络插结和通讯流。
----commandCenter():集中处理来自用户和服务器以及来自Applet内部的命令,调用相应的处理程序。
----client_ask_refresh():客户机请求刷新交谈室数据。
----client_answer_refresh():客户机接收服务器发送的交谈室数据。
----client_ask_log():申请登录到服务器。
----client_ask_join():申请加入指定交谈室。
----client_ask_pause():暂停交流。
----client_ask_continue():恢复交流。
----client_ask_newRoom():申请建立新交谈室。
----client_ask_quit():退出交谈室。
----client_ask_text():发送用户输入的文字信息。
----client_answer_text():接收服务器转发的其他用户的文字信息。
----client_answer_draw():接收服务器转发的其他用户的图形信息。
----refreshRoomList():显示交谈室列表。
----refreshUserList():显示指定交谈室中的用户列表。
----printChat_Area():将该用户和来自服务器的其他用户的输入的文字用指定格式显示在Applet的交谈文本框中。
----sendText():判断用户输入的文字是否为有效字符串,若有效则调用发送文字函数。
----drawBoard_Canvas():按DataBag对象的值,在Applet的白板上绘图。
----boardCanvas_MouseDrag():当鼠标在白板上拖动时调用此函数,将鼠标轨迹包装成数据包发送给后台网络传输线程。
----logButton_Clicked():当用户单击Applet的登录钮时调用此函数,建立网络插结和后台网络传输线程。
----其他一系列用户界面事件处理函数:与用户交流,接收用户输入,直接处理或调用commanCenter函数执行用户命令。
----RoomData类:存储该交谈室的主题和用户名的数据类
----addUser():在该交谈室中添加用户名。
----removeUser():在该交谈室中删除用户名。
----getUsersName():返回所有在该交谈室中的用户名。
----Rooms类:为Vector类的子类。存储所有交谈室的用户数据。
----getRoomByName():按交谈室主题返回指定交谈室的RoomData对象。
----addElement():添加RoomData对象。
----SendDrawData类:为Thread类的子类,实现后台网络传输线程。
----run():循环侦听来自Applet主线程的图形信息,并将其通过网络接插生成的输出流发送给服务器。
----quit():关闭该线程与Applet主线程的连接流。
----Logo类:为Canvas类的子类。用于在Applet中显示图标或版权信息。
----此外程序中还定义了几个异常类,可以方便程序的异常处理机制设计,增加程序的可维护性和可读性。Applet徽标的默认图形文件名是"cdownlogo.jpg"(457×60),服务器像标的默认图形文件名是"icon.gif"(19×17)。服务器默认占用的端口号为10000。以上各项可以视需要修改。
结论
----本文结合笔者的编程经验初步介绍了基于浏览器和JAVA的电子白板软件的程序设计过程,希望这些内容能够对广大软件开发人员有所帮助。欢迎大家与笔者联系(lfl@cenpok.net),就电子白板的一些问题进行切磋和交流。
----附录内容:
本电子白板系统的完整源程序。已测试通过,可以直接编译运行。
嵌入Applet的主页示范。请注意主页中Applet的参数设置。
本电子白板客户端Applet的用户界面及操作方法简介。
----附录1:源程序:
----附录3:电子白板客户端使用说明
确保白板服务器已在运行。使浏览器连接至本Applet所在主页。以下操作均在Applet界面上进行
请在用户名一栏中输入您的用户名,点击登录按钮。
在交谈室的选择栏中挑选您愿意加入的交谈室,下面的当前交谈室用户列表会显示出您所选择的交谈室中的现有用户。点击加入交谈室按钮即可加入该交谈室。
若您想创建新的交谈室,请在新交谈室主题一栏中输入新的主题,点击创建交谈室按钮即可,并且您自动成为该交谈室的一员。
加入或创建交谈室后即可与同一交谈室中的用户进行交谈和绘画。
方法如下:
在绘画白板的右侧的调色板中单击绘画需用的颜色。
在绘画白板上按住鼠标键拖动鼠标即可绘出图形。与此同时,该交谈室中的其他用户的绘画白板上将同步自动绘出这些图形。同理,您的白板上也将出现其他用户绘制的图形。
若感觉白板已较乱,则可点击清除白板图画按钮,白板会自动清屏。这个操作不会影响交谈室中的其他用户的白板。
您可在主页右下方的文本栏内输入您想对同一交谈室中其他用户说的话,输入后按回车键或点击发送按钮则发送给其他用户。本交谈室中所有用户输入的句子都将显示在白板下方的文本框内。综合使用绘画与交谈功能则可与网上其他用户方便地进行实时交流。
加入交谈室后,单击暂停交谈按钮可以暂时停止与其他用户交谈。暂停后再单击此按钮即可恢复交谈。
单击退出交谈室按钮或离开交谈室主页将退出交谈室。若需再次进入交谈室,请重新登录。
请留意主页左下方的系统信息框,这里将给出一些必要的操作提示。
作者: 刘飞龙(清华大学)