[返回]
计算机世界2001年第1期利用 Java实现网上动态实时查询
淮北矿务局安全技术培训中心 常 虹
中国人民银行六安市中心支行 张来东随着互联网技术的发展,用户不仅需要浏览网页,更想通过互联网获取动态的实时信息。利用 Java实现这种网上实时查询,无疑是首选方法。本文通过设计实时查询协议,并按协议编写查询服务器和与查询服务器会话的 Java Applet,来介绍如何实现网上实时查询。
设计实时查询协议
好的应用协议是服务器和客户进行会话的基础,并且可以简化程序编写。查询协议根据实际应用的需要,无需太复杂。本文介绍的协议是建立在 TCP/IP协议基础上的,可以不用考虑网络的实际传输、同步等问题。查询系统涉及到数据和图片显示,并且实时数据与图片相对应。数据中包含了数据类型、数据属性、在图中显示的坐标、实际数据等内容。不同的客户可能请求不同的内容。
本文设计的 ASIIC协议如下:
客户: " GT# "+图号;
服务器:图片文件名+ "# "+该图中包含的数据条数;
客户: " GD# ";
服务器: " SD"(开始发送数据),
实际数据(带有一定格式),
........
"$ " (发送数据结束 );
客户: " QT# ";
服务器:结束会话,关闭链接。
编写查询服务器
服务器主要是为给客户提供实时数据源,并根据客户的请求发送相应的实时数据。服务器的编写考虑以下问题:
1.速度:要能够及时响应所有查询,并能及时刷新实时数据。
2.资源:不能过多地占用系统资源。
3.服务线程:服务线程是服务器的核心,具体负责和客户按协议会话。服务器必须是多线程的,既要考虑同一时刻接受多个用户查询的问题,又要考虑服务中的峰值问题。
查询服务器的主要功能由类 zld_s和 Server_class实现,它们均是 Thread类的子类。类 Server_class的 init()函数进行初始化工作, run()函数用于数据刷新, DoServer()函数是将动态的实时数据发往指定的输出流。
DoServer()函数定义如下:
public void DoServer(int th,PrintStream outs){
int j,d,c;
String s;
outs.println(" SD" );
for(j=0;j
c=bq[th][j].chang_h;
d=bq[th][j].dian_h;
outs.println(bq[th][j].Getdata());
//实时数据被定义成了一个类,存放在动态数组 bq[][]中
}
outs.println("$ ");
outs.flush();
}//end DoServer
zld_s类的定义如下:
public class zld_s extends Thread {
public final static int DFPORT = 8987;//端口号
ServerSocket theServer;
//同时启动的服务线程数,即同一时刻支持的查询请求
static int num_threads = 25;
public static Server_class sc ;
public static void main(String[] args){
int port = DFPORT;
sc = new Server_class();
sc.init();
sc.start();
try {
ServerSocket ssocket = new ServerSocket(port);
System.out.println(ssocket);
for (int i = 0; i < num_threads; i++ ) {
zld_s zlds = new zld_s(ssocket);
zlds.start();
}//在服务器上建立一个服务线程池( spool)
System.out.println("实时查询服务器已经运行! " );
}catch (IOException e) {
System.out.println("实时查询服务器无法运行! " );
System.exit(0);
}
//master控制类,便于服务器程序的正常退出
master m=new master(sc);
m.start();
}
public zld_s(ServerSocket ss) {
theServer = ss;
}
public void run() {
String dfromc,tp=null;
sssjycyx ycyx;
String th;
int intth=0;
while (true) {
try {
Socket s = theServer.accept();
System.out.println(s);
PrintStream outs = new PrintStream(s.getOutputStream());
DataInputStream ins = new DataInputStream(s.getInputStream());
while(true){
dfromc = ins.readLine();
tp = dfromc.substring(0,3);
if(tp.equals(" GT# " )){
th = dfromc.substring(3).trim();
intth =(new Integer(th)).intValue();
ycyx = new sssjycyx(intth);
tp = (new Integer(sc.th_bq_num[intth])).toString();
outs.println(ycyx.readtm()+ "# "+ tp);
outs.flush();
}else if(tp.equals(" GD# " )){
sc.DoServer(intth,outs);
outs.flush();
}else if(tp.equals(" QT# " )){
System.out.println(s.toString()+ " off line," );
s.close();
s=null;
break;
} //按协议和客户会话
} // end while
} // end try
//catch(InterruptedException e){}
catch (IOException e) {
}
} // end while
}// end run
public String getw(){
StringBuffer s = new StringBuffer();
s .append(" ZLD Ycyx Server. Version 1.0\n" );
s.append(" @\" " );
s.append(" 1999 Goldsoft Studio,All Rights
Reserved \" \n" );
return s.toString();
}
}//end zld_s类
编写 Java Applet
Applet用来向查询服务器发送查询请求,并显示实时查询结果。为保证显示效果,一般需要重载 update()函数,以及使用双缓存技术和多线程。笔者在实际中使用了以上技术,仍然发现由于同步问题使部分数据显示时出现闪烁。
Java Applet中使用的主要函数部分代码如下:
public void init(){
temp=createImage(bounds().width,bounds().height); tt=temp.getGraphics();//建立显示缓存
//建立媒体跟踪器,跟踪图像装入
tker = new MediaTracker(this);
......
tm = chgda();
//取图中标签数
bqn = (new Integer(tm.substring(tm.indexOf("# " )+ 1))).intValue();
data = new String[bqn];
tm = tm.substring(0,tm.indexOf("# " ));
//根据 tm参数取图
sjbj = getImage(getDocumentBase(),tm);
tker.addImage(sjbj,8);
try {
int i=0;
for(i=0;i< 9;i++ )
tker.waitForID(i);
} catch (InterruptedException e) {
return;
}
kh.out.println(" GD# " );
kh.out.flush();
}//end init()
//按协议和服务器会话
public void run(){
String dfs;
int i = 0;
for(;;){
dfs=chgda();
if(dfs.length()>0){
if (dfs.equals(" SD" )){
i = 0;
}else if(dfs.equals("$ " )){
kh.out.println(" GD# " );
kh.out.flush();
drflush(); //刷新显示
}else {
data[i]=dfs;
i=i+ 1;
} //end if
} //end if
}//end for
}//end run
synchronized public void drflush(){
// synchronized用来防止数据显示出现闪烁
int i;
tt.clearRect(0,0,bounds().width,bounds().height);
tt.drawImage(sjbj,0,0,this);
for(i=0;i< bqn;i++ ){
drawSwitch(data[i],tt);
}
repaint();
} //end drflush
public synchronized void update(Graphics g){
g.drawImage(temp,0,0,null);
}//end update()
由于安全等因素,实时查询服务器必须和 Web服务器运行在同一台机器上,要有相同的 IP地址,否则实际查询时, Applet无法链接查询服务器,如果从本地机器上启动 Applet则没有此限制。