友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
一世书城 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

Java编程思想第4版[中文版](PDF格式)-第178章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




个Java 应用。事实上,我们在这儿已完全跳过了 Web 服务器,仅仅需要从程序片到服务器上运行的 Java 应 

用之间建立一个连接即可。  

正如大家不久就会体验到的那样,尽管看起来非常简单,但实际上有一些意想不到的问题使局面显得稍微有 

些复杂。用 Java 1。1 写程序片是最理想的,但实际上却经常行不通。到本书写作的时候,拥有 Java 1。1 能 

力的浏览器仍为数不多,而且即使这类浏览器现在非常流行,仍需考虑照顾一下那些升级缓慢的人。所以从 

安全的角度看,程序片代码最好只用Java 1。0 编写。基于这一前提,我们不能用 JAR 文件来合并(压缩)程 

序片中的。class 文件。所以,我们应尽可能减少。class 文件的使用数量,以缩短下载时间。  

好了,再来说说我用的 Web 服务器(写这个示范程序时用的就是它)。它确实支持Java,但仅限于 Java  

1。0!所以服务器应用也必须用Java 1。0 编写。  



15。5。1 服务器应用  



现在讨论一下服务器应用(程序)的问题,我把它叫作NameCollecor (名字收集器)。假如多名用户同时尝 

试提交他们的E…mail 地址,那么会发生什么情况呢?若 NameCollector 使用TCP/IP 套接字,那么必须运用 

早先介绍的多线程机制来实现对多个客户的并发控制。但所有这些线程都试图把数据写到同一个文件里,其 

中保存了所有E…mail 地址。这便要求我们设立一种锁定机制,保证多个线程不会同时访问那个文件。一个 

 “信号机”可在这里帮助我们达到目的,但或许还有一种更简单的方式。  

如果我们换用数据报,就不必使用多线程了。用单个数据报即可“侦听”进入的所有数据报。一旦监视到有 

进入的消息,程序就会进行适当的处理,并将答复数据作为一个数据报传回原先发出请求的那名接收者。若 

数据报半路上丢失了,则用户会注意到没有答复数据传回,所以可以重新提交请求。  

服务器应用收到一个数据报,并对它进行解读的时候,必须提取出其中的电子函件地址,并检查本机保存的 

数据文件,看看里面是否已经包含了那个地址(如果没有,则添加之)。所以我们现在遇到了一个新的问 

题。Java 1。0 似乎没有足够的能力来方便地处理包含了电子函件地址的文件(Java 1。1 则不然)。但是,用 

C 轻易就可以解决这个问题。因此,我们在这儿有机会学习将一个非 Java 程序同 Java 程序连接的最简便方 

式。程序使用的Runtime 对象包含了一个名为exec()的方法,它会独立机器上一个独立的程序,并返回一个 

Process (进程)对象。我们可以取得一个OutputStream,它同这个单独程序的标准输入连接在一起;并取 

得一个 InputStream,它则同标准输出连接到一起。要做的全部事情就是用任何语言写一个程序,只要它能 

从标准输入中取得自己的输入数据,并将输出结果写入标准输出即可。如果有些问题不能用Java 简便与快速 

地解决(或者想利用原有代码,不想改写),就可以考虑采用这种方法。亦可使用Java 的“固有方法” 

 (Native Method ),但那要求更多的技巧,大家可以参考一下附录A 。  

  

1。 C 程序  

这个非 Java 应用是用 C 写成,因为 Java 不适合作 CGI 编程;起码启动的时间不能让人满意。它的任务是管 

理电子函件(E…mail )地址的一个列表。标准输入会接受一个E…mail 地址,程序会检查列表中的名字,判断 

是否存在那个地址。若不存在,就将其加入,并报告操作成功。但假如名字已在列表里了,就需要指出这一 



                                                                552 


…………………………………………………………Page 554……………………………………………………………

点,避免重复加入。大家不必担心自己不能完全理解下列代码的含义。它仅仅是一个演示程序,告诉你如何 

用其他语言写一个程序,并从 Java 中调用它。在这里具体采用何种语言并不重要,只要能够从标准输入中读 

取数据,并能写入标准输出即可。  

  

//: Listmgr。c  

// Used by NameCollector。java to manage   

// the email list file on the server  

#include   

#include   

#include   

#define BSIZE 250  

  

int alreadyInList(FILE* list; char* name) {  

  char lbuf'BSIZE';  

  // Go to the beginning of the list:  

  fseek(list; 0; SEEK_SET);  

  // Read each line in the list:  

  while(fgets(lbuf; BSIZE; list)) {  

    // Strip off the newline:  

    char * newline = strchr(lbuf; 'n');  

    if(newline != 0)   

      *newline = '0';  

    if(strcmp(lbuf; name) == 0)  

      return 1;  

  }  

  return 0;  

}  

  

int main() {  

  char buf'BSIZE';  

  FILE* list = fopen(〃emlist。txt〃; 〃a+t〃);  

  if(list == 0) {  

    perror(〃could not open emlist。txt〃);  

    exit(1);  

  }  

  while(1) {  

    gets(buf); /* From stdin */  

    if(alreadyInList(list; buf)) {  

      printf(〃Already in list: %s〃; buf);  

      fflush(stdout);  

    }  

    else {  

      fseek(list; 0; SEEK_END);  

      fprintf(list; 〃%sn〃; buf);  

      fflush(list);  

      printf(〃%s added to list〃; buf);  

      fflush(stdout);  

    }  

  }  

} ///:~  

  

该程序假设 C 编译器能接受'//'样式注释(许多编译器都能,亦可换用一个C++编译器来编译这个程序)。 



                                                                                             553 


…………………………………………………………Page 555……………………………………………………………

如果你的编译器不能接受,则简单地将那些注释删掉即可。  

文件中的第一个函数检查我们作为第二个参数(指向一个 char 的指针)传递给它的名字是否已在文件中。在 

这儿,我们将文件作为一个FILE 指针传递,它指向一个已打开的文件(文件是在main()中打开的)。函数 

fseek()在文件中遍历;我们在这儿用它移至文件开头。fgets()从文件 list 中读入一行内容,并将其置入缓 

冲区 lbuf——不会超过规定的缓冲区长度BSIZE 。所有这些工作都在一个while 循环中进行,所以文件中的 

每一行都会读入。接下来,用 strchr()找到新行字符,以便将其删掉。最后,用 strcmp()比较我们传递给函 

数的名字与文件中的当前行。若找到一致的内容,strcmp()会返回 0。函数随后会退出,并返回一个1,指出 

该名字已经在文件里了(注意这个函数找到相符内容后会立即返回,不会把时间浪费在检查列表剩余内容的 

上面)。如果找遍列表都没有发现相符的内容,则函数返回0。  

在main()中,我们用 fopen()打开文件。第一个参数是文件名,第二个是打开文件的方式;a+表示“追 

加”,以及“打开”(或“创建”,假若文件尚不存在),以便到文件的末尾进行更新。fopen()函数返回的 

是一个FILE 指针;若为 0,表示打开操作失败。此时需要用 perror()打印一条出错提示消息,并用 exit() 

中止程序运行。  

如果文件成功打开,程序就会进入一个无限循环。调用gets(buf)的函数会从标准输入中取出一行(记住标 

准输入会与 Java 程序连接到一起),并将其置入缓冲区buf 中。缓冲区的内容随后会简单地传递给 

alreadyInList()函数,如内容已在列表中,printf()就会将那条消息发给标准输出(Java 程序正在监视 

它)。fflush()用于对输出缓冲区进行刷新。  

如果名字不在列表中,就用fseek()移到列表末尾,并用 fprintf()将名字“打印”到列表末尾。随后,用 

printf()指出名字已成功加入列表(同样需要刷新标准输出),无限循环返回,继续等候一个新名字的进 

入。  

记住一般不能先在自己的计算机上编译此程序,再把编译好的内容上载到 Web 服务器,因为那台机器使用的 

可能是不同类的处理器和操作系统。例如,我的Web 服务器安装的是 Intel 的CPU,但操作系统是Linux,所 

以必须先下载源码,再用远程命令(通过telnet)指挥Linux 自带的C 编译器,令其在服务器端编译好程 

序。  

  

2。 Java 程序  

这个程序先启动上述的 C 程序,再建立必要的连接,以便同它“交谈”。随后,它创建一个数据报套接字, 

用它“监视”或者“侦听”来自程序片的数据报包。  

  

//: NameCollector。java  

// Extracts email names from datagrams and stores  

// them inside a file; using Java 1。02。  

import java。*;  

import java。io。*;  

import java。util。*;  

  

public class NameCollector {  

  final static int COLLECTOR_PORT = 8080;  

  final static int BUFFER_SIZE = 1000;  

  byte'' buf = new byte'BUFFER_SIZE';  

  DatagramPacket dp =   

    new DatagramPacket(buf; buf。length);  

  // Can listen & send on the same socket:  

  DatagramSocket socket;  

  Process listmgr;  

  PrintStream nameList;  

  DataInputStream addResult;  

  public NameCollector() {  

    try {  

      listmgr =  

        Runtime。getRuntime()。exec(〃listmgr。exe〃);  

      nameList = new PrintStream(   



                                                                                   554 


…………………………………………………………Page 556……………………………………………………………

        new BufferedOutputStream(  

          listmgr。getOutputStream()));  

      addResult = new DataInputStream(  

        new BufferedInputStream(  

          listmgr。getInputStream()));  

  

    } catch(IOException e) {  

      System。err。println(  

        〃Cannot start listmgr。exe〃);  

      System。exit(1);  

    }  

    try {  

      socket =  

        new DatagramSocket(COLLECTOR_PORT);  

      System。out。println( 
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!