[返回]
计算机世界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则没有此限制。