Java中通过数据报包输送对象

原创 2001年05月19日 10:53:00
Java 1.1 吸引人的特性之一就是新增了 ObjectInputStreamObjectOutputStream 这两个类。有了这个新的 API(ObjectOutputStream 类中的 writeObject(Object o) 方法和 ObjectInputStream 类中的 object readObject()),您就可以随时获取运行对象的快照,而不管它的对象图有多复杂。因为这种快照是通过 ObjectOutputStream 类(OutputStream 类的子类)提供的,所以您很容易将它包装在其他输出流中,从而实现所需的任何功能(如 FileOutputStream)。

Java 1.1 中提供的这些新类使得在网上传输运行对象成为可能。为此,该对象以及那些被引用的对象必须可序列化 -- 即能够转换为字节流。幸运的是,在 Java 1.1 中,多数内建的类都是可序列化的。但是,某些类是不可序列化的(Object 类就是一个典型的例子)。不过别担心。如果您的类继承自不可序列化的类,您还可以用 ObjectOutputStream 类中的 defaultWriteObject() 方法实现序列化,随后还可用 ObjectInputStream 类中的 defaultReadObject() 方法解除序列化。

一旦进行了序列化,对象就可在网上传输了。以下示例说明生成可序列化对象并通过流套接字发送它的方法:

//对象输出
import java.net.*;
import java.io.*;

//要发送的类样例:Factory
class Factory implements Serializable
{
  private void writeObject(ObjectOutputStream out) throws IOException
  {
    out.defaultWriteObject();
  }

  private void readObject(ObjectInputStream in)
               throws IOException, ClassNotFoundException
  {
    in.defaultReadObject();
  }
}

public class ShowObjOutput
{
  public static void main(String[] arg)
  {
    try
    {
      ObjectOutputStream os;
      Socket sock = new Socket("panda.cs.uno.edu", 6000); //panda 为主机名
      Factory fa = new Factory();

      os = new ObjectOutputStream( new
             BufferedOutputStream(sock.getOutputStream()));
      os.writeObject(fa);
    }
    catch (IOException ex)
    {}
  }
}

下一示例说明了 ObjectInputStream 如何从流套接字接收对象:

//对象输入
import java.net.*;
import java.io.*;

public class ShowObjInput
{
  public static void main(String[] arg)
  {
    try
    {
      ObjectInputStream is;
      ServerSocket servSock = new ServerSocket(6000);
      Sock sock;

      sock = servSock.accept();
      is = new ObjectInputStream( new
               BufferedInputStream(sock.getInputStream()));
      Factory o = (Factory)is.readObject();
    }
    catch (IOException ex)
    {}
  }
}

除了紧密耦合的套接字之外,Java 还提供了 DatagramSocket 类来支持无连接的数据报通信。我们可以使用数据报通信完成对象输入/输出吗?完成此功能不象使用流套接字那么简单?问题在于 DatagramSocket 未连接到任何流;为了执行发送和接收操作,DatagramSocket 使用一个字节数组作为参数。

可以想像,为了构造数据报包,对象必须转换成字节数组。如果对象涉及到一个复杂的对象图,这种转换可能极难完成。以前发表的许多文章讨论了实现对象序列化的方法 -- 即将 Java 对象打包(序列化)成字节流以及将字节流解包为 Java 对象。然而,由于对象图可能很复杂,则将常规对象图转换成字节数组可能需要编写大量的代码。

那么,如何避免编写复杂的打包代码呢?以下提供了一种利用数据报包传输对象的方法,而且无需编写打包代码。


上图说明了使用数据报传输对象时的数据流。按以下给出的七个步骤,您就能实现这个数据流,它可传输任何类型的对象,myObject

  • 第一步。准备:通过实现 Serializable 接口使您的对象(比方说 myObject)可序列化。

  • 第二步。创建 ByteArrayOutputStream 对象,比方说,名为 baoStream

  • 第三步。用 baoStream 构造一个 ObjectOutputStream 对象,比方说 ooStream

  • 第四步。通过调用 ooStreamwriteObject() 方法将对象 myObject 写入 baoStream 中。

  • 第五步。使用 baoStreamtoByteArray() 方法从 baoStream 中检索字节数组缓冲区。

  • 第六步。使用由第五步检索到的数组缓冲区构造 DatagramPacket,比方说 dPacket

  • 第七步。通过调用 DatagramSocketsend() 方法发送 dPacket

要接收对象,以逆序完成以上所列各步,用 ObjectInputStream 代替 ObjectOutputStream,同时用 ByteArrayInputStream 代替 ByteArrayOutputStream

当用套接字编程时,sendTo 是无连接协议中使用的一个标准函数。为了能够传输对象,我重写了这个函数。以下代码示例展示了如何在 Sender 类中实现 send 方法:

import java.io.*;
import java.net.*;

public class Sender
{
  public void sendTo(Object o, String hostName, int desPort)
  {
    try
    {
      InetAddress address = InetAddress.getByName(hostName);
      ByteArrayOutputStream byteStream = new
          ByteArrayOutputStream(5000);
      ObjectOutputStream os = new ObjectOutputStream(new
                              BufferedOutputStream(byteStream));
      os.flush();
      os.writeObject(o);
      os.flush();

      // 检索字节数组
      byte[] sendBuf = byteStream.toByteArray();
      DatagramPacket packet = new DatagramPacket(
                          sendBuf, sendBuf.length, address, desPort);
      int byteCount = packet.getLength();
      dSock.send(packet);
      os.close();
    }
    catch (UnknownHostException e)
    {
      System.err.println("Exception: " + e);
      e.printStackTrace ();
    }
    catch (IOException e)
    { e.printStackTrace(); }
  }
}

以下代码清单说明了如何在 Receiver 类中实现 receive 方法。recvObjFrom 方法是供接收者接收对象的。您应在您的代码中包含此方法以接收运行时对象。

import java.io.*;
import java.net.*;

public class Receiver
{
  public Object recvObjFrom()
  {
    try
    {
      byte[] recvBuf = new byte[5000];
      DatagramPacket packet = new DatagramPacket(recvBuf,
                                                 recvBuf.length);

      dSock.receive(packet);
      int byteCount = packet.getLength();

      ByteArrayInputStream byteStream = new
                                  ByteArrayInputStream(recvBuf);

      ObjectInputStream is = new
           ObjectInputStream(new BufferedInputStream(byteStream));
      Object o = is.readObject();
      is.close();
      return(o);
    }
    catch (IOException e)
    {
      System.err.println("Exception: " + e);
      e.printStackTrace ();
    }
    catch (ClassNotFoundException e)
    { e.printStackTrace(); }

    return(null);
  }
}

人们可能会担心字节数组的大小 -- 因为当您构造 ByteArrayOutputStreamByteArrayInputStream 时,您必须指定数组的大小。既然您不知道运行时对象的大小,您就很难指定其大小。运行时对象的大小通常是不可预知的。幸运的是,Java 的 ByteArrayInputStreamByteArrayOutputStream 类可根据需要自动扩展其大小。

小结
通过利用 Java 的内建序列化代码,我阐述了一种使用数据报包传输对象的方法。正如您所见,技巧就是使用字节数组流将对象流化为字节数组。

Java中的对象,包,类

找对象:对象可以是问题域中的出现的任何人、事物或者实体,简单点说就是“东西”; 在已经找到问题域中的对象后,我们就要编写一个类来描述每个对象的属性和行为; 属性是指对象身上的有什么值数据; 行为是对象...
  • Momeory
  • Momeory
  • 2016年03月07日 21:39
  • 1489

第八节 包和引入

本节主要内容 包的作用与定义包的作用域与引入(import)的使用方法访问控制包对象import高级特性内部类 包的作用与定义 同Java中的包、C++中的命名空间一样,Scala中...
  • houjun1988325
  • houjun1988325
  • 2017年01月23日 15:08
  • 116

Javascript和Java中闭包的理解

一。Javascript中闭包: 1.变量的作用域   要理解闭包,首先必须理解Javascript特殊的变量作用域。   变量的作用域无非就是两种:全局变量和局部变量。      Java...
  • wangwei249
  • wangwei249
  • 2017年04月13日 14:02
  • 873

UML之对象图和包图

UML的九种图基本都已经介绍完了,那么我们回过头再来研究一下对象图和包图。          一、对象图         谈到对象,我们不得不说一下对象,对象(Object)是对象类的实例(Ins...
  • u013037201
  • u013037201
  • 2014年11月20日 19:53
  • 2041

js---闭包和面向对象编程

这两个概念理解起来不容易,翻查了很多资料,几乎耗费了我一天的时间来理解它,感觉自己都快走火入魔了。不过最终有所了悟,一番付出还是有所收获的。(1)闭包概念很多书上关于闭包的定义直接阅读的话很难理解,下...
  • liuxuan12417
  • liuxuan12417
  • 2016年11月24日 22:28
  • 686

java对象存储方式

1.寄存器。这是最快的存储区,因为它是直接存储在处理器内部,由于寄存器的数量有限,寄存器会根据需要来进行分配,在程序中我们不能直接控制,也无法感受到寄存器的存在的任何迹象;然而C和C++允许向寄存器建...
  • u010507622
  • u010507622
  • 2013年07月30日 17:34
  • 845

Java创建和解析Json数据方法(二)——org.json包的使用

org.json包的使用 主要介绍常用的一些类如:JSONObject、JSONArray、JSONStringer等类的一些用法; 介绍了如何将Map、Collection、Bean等对象转化为js...
  • Zen99T
  • Zen99T
  • 2015年12月18日 14:38
  • 12680

java关于new出一个对象的例子

首先看下面一段代码: public class BB { String str = new String("good"); char[] ch = { 'a', 'b', 'c' }; pu...
  • u013936108
  • u013936108
  • 2014年04月12日 00:50
  • 1894

java system.out.println() 详解(其中包,类,对象的关系) system.out 和 printstream类的关系浅谈

java.lang.system.out.printlb() java.lang 与 system.out.println()的关系 首先lang是一个包,system是类,Out是对象,...
  • evan_0097
  • evan_0097
  • 2016年10月04日 11:07
  • 1232

Java面向对象 包

 黑马程序员  Java面向对象  包
  • u014756827
  • u014756827
  • 2014年05月30日 13:44
  • 264
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java中通过数据报包输送对象
举报原因:
原因补充:

(最多只允许输入30个字)