八宝书库 > 文学其他电子书 > Java编程思想第4版[中文版](PDF格式) >

第143部分

Java编程思想第4版[中文版](PDF格式)-第143部分

小说: Java编程思想第4版[中文版](PDF格式) 字数: 每页4000字

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




    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(  

        〃NameCollector Server started〃);  

      while(true) {  

        // Block until a datagram appears:  

        socket。receive(dp);  

        String rcvd = new String(dp。getData();  

            0; 0; dp。getLength());  

        // Send to listmgr。exe standard input:  

        nameList。println(rcvd。trim());  

        nameList。flush();  

        byte'' resultBuf = new byte'BUFFER_SIZE';  

        int byteCount =   

          addResult。read(resultBuf);  

        if(byteCount != …1) {  

          String result =   

            new String(resultBuf; 0)。trim();  

          // Extract the address and port from   

          // the received datagram to find out   

          // where to send the reply:  

          InetAddress senderAddress =  

            dp。getAddress();  

          int senderPort = dp。getPort();  

          byte'' echoBuf = new byte'BUFFER_SIZE';  

          result。getBytes(  

            0; byteCount; echoBuf; 0);  

          DatagramPacket echo =  

            new DatagramPacket(  

              echoBuf; echoBuf。length;  

              senderAddress; senderPort);  

          socket。send(echo);  

        }  

        else  

          System。out。println(  

            〃Unexpected lack of result from 〃 +  

            〃listmgr。exe〃);  

      }  

    } catch(SocketException e) {  

      System。err。println(〃Can't open socket〃);  



                                                                                          555 


…………………………………………………………Page 557……………………………………………………………

      System。exit(1);  

    } catch(IOException e) {  

      System。err。println(〃munication error〃);  

      e。printStackTrace();  

    }  

  }  

  public static void main(String'' args) {  

    new NameCollector();  

  }  

} ///:~  

  

NameCollector 中的第一个定义应该是大家所熟悉的:选定端口,创建一个数据报包,然后创建指向一个 

DatagramSocket 的句柄。接下来的三个定义负责与C 程序的连接:一个 Process 对象是 C 程序由 Java 程序 

启动之后返回的,而且那个Process 对象产生了 InputStream 和OutputStream,分别代表 C 程序的标准输出 

和标准输入。和Java IO 一样,它们理所当然地需要“封装”起来,所以我们最后得到的是一个 

PrintStream 和 DataInputStream。  

这个程序的所有工作都是在构建器内进行的。为启动C 程序,需要取得当前的 Runtime 对象。我们用它调用 

exec(),再由后者返回Process 对象。在Process 对象中,大家可看到通过一简单的调用即可生成数据流: 

getOutputStream()和 getInputStream()。从这个时候开始,我们需要考虑的全部事情就是将数据传给数据 

流nameList ,并从addResult 中取得结果。  

和往常一样,我们将DatagramSocket 同一个端口连接到一起。在无限while 循环中,程序会调用 

receive()——除非一个数据报到来,否则receive()会一起处于“堵塞”状态。数据报出现以后,它的内容 

会提取到String rcvd 里。我们首先将该字串两头的空格剔除(trim),再将其发给C 程序。如下所示:  

nameList。println(rcvd。trim());  

之所以能这样编码,是因为Java 的exec()允许我们访问任何可执行模块,只要它能从标准输入中读,并能 

向标准输出中写。还有另一些方式可与非Java 代码“交谈”,这将在附录A 中讨论。  

从C 程序中捕获结果就显得稍微麻烦一些。我们必须调用 read(),并提供一个缓冲区,以便保存结果。 

read()的返回值是来自C 程序的字节数。若这个值为…1,意味着某个地方出现了问题。否则,我们就将 

resultBuf (结果缓冲区)转换成一个字串,然后同样清除多余的空格。随后,这个字串会象往常一样进入一 

个DatagramPacket,并传回当初发出请求的那个同样的地址。注意发送方的地址也是我们接收到的 

DatagramPacket 的一部分。  

记住尽管C 程序必须在 Web 服务器上编译,但 Java 程序的编译场所可以是任意的。这是由于不管使用的是什 

么硬件平台和操作系统,编译得到的字节码都是一样的。就就是Java 的“跨平台”兼容能力。  



15。5。2 NameSender 程序片  



正如早先指出的那样,程序片必须用Java 1。0 编写,使其能与绝大多数的浏览器适应。也正是由于这个原 

因,我们产生的类数量应尽可能地少。所以我们在这儿不考虑使用前面设计好的Dgram 类,而将数据报的所 

有维护工作都转到代码行中进行。此外,程序片要用一个线程监视由服务器传回的响应信息,而非实现 

Runnable 接口,用集成到程序片的一个独立线程来做这件事情。当然,这样做对代码的可读性不利,但却能 

产生一个单类(以及单个服务器请求)程序片:  

  

//: NameSender。java  

// An applet that sends an email address  

// as a datagram; using Java 1。02。  

import java。awt。*;  

import java。applet。*;  

import java。*;  

import java。io。*;  

  

public class NameSender extends Applet   

    implements Runnable {  

  private Thread pl = null;  



                                                                                    556 


…………………………………………………………Page 558……………………………………………………………

  private Button send = new Button(  

    〃Add email address to mailing list〃);  

  private TextField t = new TextField(  

    〃type your email address here〃; 40);  

  private String str = new String();  

  private Label   

    l = new Label(); l2 = new Label();  

  private DatagramSocket s;   

  private InetAddress hostAddress;  

  private byte'' buf =   

    new byte'NameCollector。BUFFER_SIZE';  

  private DatagramPacket dp =  

    new DatagramPacket(buf; buf。length);  

  private int vcount = 0;  

  public void init() {  

    setLayout(new BorderLayout());  

    Panel p = new Panel();  

    p。setLayout(new GridLayout(2; 1));  

    p。add(t);  

    p。add(send);  

    add(〃North〃; p);  

    Panel labels = new Panel();  

    labels。setLayout(new GridLayout(2; 1));  

    labels。add(l);  

    labe ls。add(l2);  

    add(〃Center〃; labels);  

    try {  

      // Auto…assign port number:  

      s = new DatagramSocket();  

      hostAddress = InetAddress。getByName(  

        getCodeBase()。getHost());  

    } catch(UnknownHostException e) {  

      l。setText(〃Cannot find host〃);  

    } catch(SocketException e) {  

      l。setText(〃Can't open socket〃);  

    }   

    l。setText(〃Ready to send your email address〃);  


返回目录 上一页 下一页 回到顶部 0 1

你可能喜欢的