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

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

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




们不需要在这个问题上纠缠不清。这一点在下例里将有很明确的说明。该例类似于前面针对 TCP 套接字的 

MultiJabberServer 和MultiJabberClient 例子。多个客户都会将数据报发给服务器,后者会将其反馈回最 

初发出消息的同样的客户。  

为简化从一个String 里创建 DatagramPacket 的工作(或者从DatagramPacket 里创建 String),这个例子 

首先用到了一个工具类,名为Dgram:  

  

//: Dgram。java  

// A utility class to convert back and forth  

// Between Strings and DataGramPackets。  

import java。*;  

  

public class Dgram {  

  public static DatagramPacket toDatagram(  

    String s; InetAddress destIA; int destPort) {  

    // Deprecated in Java 1。1; but it works:  

    byte'' buf = new byte's。length() + 1';  

    s。getBytes(0; s。length(); buf; 0);  

    // The correct Java 1。1 approach; but it's  

    // Broken (it truncates the String):  

    // byte'' buf = s。getBytes();  

    return new DatagramPacket(buf; buf。length;   

      destIA; destPort);  

  }  

  public static String toString(DatagramPacket p){  

    // The Java 1。0 approach:  

    // return new String(p。getData();   

    //  0; 0; p。getLength());  

    // The Java 1。1 approach:  

    return   

      new String(p。getData(); 0; p。getLength());  

  }  

} ///:~  

  

Dgram 的第一个方法采用一个String、一个 InetAddress 以及一个端口号作为自己的参数,将String 的内容 

复制到一个字节缓冲区,再将缓冲区传递进入 DatagramPacket 构建器,从而构建一个 DatagramPacket。注 

意缓冲区分配时的〃+1〃——这对防止截尾现象是非常重要的。String 的getByte()方法属于一种特殊操作, 

能将一个字串包含的char 复制进入一个字节缓冲。该方法现在已被“反对”使用;Java 1。1 有一个“更 

好”的办法来做这个工作,但在这里却被当作注释屏蔽掉了,因为它会截掉String 的部分内容。所以尽管我 

们在Java 1。1 下编译该程序时会得到一条“反对”消息,但它的行为仍然是正确无误的(这个错误应该在你 

读到这里的时候修正了)。  

Dgram。toString()方法同时展示了Java 1。0 的方法和Java 1。1 的方法(两者是不同的,因为有一种新类型 

的String 构建器)。  

下面是用于数据报演示的服务器代码:  

//: ChatterServer。java  

// A server that echoes datagrams  

import java。*;  

import java。io。*;  

import java。util。*;  



                                                                                          548 


…………………………………………………………Page 550……………………………………………………………

  

public class ChatterServer {  

  static final int INPORT = 1711;  

  private byte'' buf = new byte'1000';  

  private DatagramPacket dp =   

    new DatagramPacket(buf; buf。length);  

  // Can listen & send on the same socket:  

  private DatagramSocket socket;  

  

  public ChatterServer() {  

    try {  

      socket = new DatagramSocket(INPORT);  

      System。out。println(〃Server started〃);  

      while(true) {  

        // Block until a datagram appears:  

        socket。receive(dp);  

        String rcvd = Dgram。toString(dp) +  

          〃; from address: 〃 + dp。getAddress() +  

          〃; port: 〃 + dp。getPort();  

        System。out。println(rcvd);  

        String echoString =   

          〃Echoed: 〃 + rcvd;  

        // Extract the address and port from the  

        // received datagram to find out where to  

        // send it back:  

        DatagramPacket echo =   

          Dgram。toDatagram(echoString;  

            dp。getAddress(); dp。getPort());  

        socket。send(echo);  

      }  

    } catch(SocketException e) {  

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

      System。exit(1);  

    } catch(IOException e) {  

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

      e。printStackTrace();  

    }  

  }  

  public static void main(String'' args) {  

    new ChatterServer();  

  }  

} ///:~  

  

ChatterServer 创建了一个用来接收消息的DatagramSocket (数据报套接字),而不是在我们每次准备接收 

一条新消息时都新建一个。这个单一的DatagramSocket 可以重复使用。它有一个端口号,因为这属于服务 

器,客户必须确切知道自己把数据报发到哪个地址。尽管有一个端口号,但没有为它分配因特网地址,因为 

它就驻留在“这”台机器内,所以知道自己的因特网地址是什么(目前是默认的 localhost)。在无限while 

循环中,套接字被告知接收数据(receive())。然后暂时挂起,直到一个数据报出现,再把它反馈回我们希 

望的接收人——DatagramPacket dp——里面。数据包(Packet)会被转换成一个字串,同时插入的还有数据 

包的起源因特网地址及套接字。这些信息会显示出来,然后添加一个额外的字串,指出自己已从服务器反馈 

回来了。  

大家可能会觉得有点儿迷惑。正如大家会看到的那样,许多不同的因特网地址和端口号都可能是消息的起源 



                                                                                          549 


…………………………………………………………Page 551……………………………………………………………

地——换言之,客户程序可能驻留在任何一台机器里(就这一次演示来说,它们都驻留在 localhost 里,但 

每个客户使用的端口编号是不同的)。为了将一条消息送回它真正的始发客户,需要知道那个客户的因特网 

地址以及端口号。幸运的是,所有这些资料均已非常周到地封装到发出消息的DatagramPacket 内部,所以我 

们要做的全部事情就是用getAddress()和getPort()把它们取出来。利用这些资料,可以构建 

DatagramPacket echo——它通过与接收用的相同的套接字发送回来。除此以外,一旦套接字发出数据报,就 

会添加“这”台机器的因特网地址及端口信息,所以当客户接收消息时,它可以利用 getAddress()和 

getPort()了解数据报来自何处。事实上,getAddress()和 getPort()唯一不能告诉我们数据报来自何处的前 

提是:我们创建一个待发送的数据报,并在正式发出之前调用了getAddress()和getPort()。到数据报正式 

发送的时候,这台机器的地址以及端口才会写入数据报。所以我们得到了运用数据报时一项重要的原则:不 

必跟踪一条消息的来源地!因为它肯定保存在数据报里。事实上,对程序来说,最可靠的做法是我们不要试 

图跟踪,而是无论如何都从目标数据报里提取出地址以及端口信息(就象这里做的那样)。  

为测试服务器的运转是否正常,下面这程序将创建大量客户(线程),它们都会将数据报包发给服务器,并 

等候服务器把它们原样反馈回来。  

  

//: ChatterClient。java  

// Tests the ChatterServer by starting multiple   

// clients; each of which sends datagrams。  

import java。lang。Thread;  

import java。*;  

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