分享
 
 
 

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

王朝java/jsp·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Java 1.1 吸引人的特性之一就是新增了 ObjectInputStream 和 ObjectOutputStream 这两个类。有了这个新的 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。

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

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

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

第七步。通过调用 DatagramSocket 的 send() 方法发送 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);

}

}

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

小结

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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有