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 的内建序列化代码,我阐述了一种使用数据报包传输对象的方法。正如您所见,技巧就是使用字节数组流将对象流化为字节数组。
相关推荐
解析ARP数据包---计算机网络课程设计
工控协议-dnp3-数据包-0-30功能码
互联网零售行业季度数据包-20200716-华菁证券-37页.pdf
JAVA 面向对象程序设计教程 第13章 Java网络编程 第13章-Java网络编程-Java面向对象程序设计教程-微课视频版-程杰-清华大学出版社全文共17页,当前为第1页。 第13章 Java网络编程 第13章-Java网络编程-Java面向对象...
手把手教你捕获数据包-winpcap-混杂模式设定
ecshop大朴简洁版单独数据包(utf-8).zip
24L01+带数据包的ACK-用于双向传输.doc
python基础教程之获取本机ip数据包示例-电脑资料.docxpython基础教程之获取本机ip数据包示例-电脑资料.docxpython基础教程之获取本机ip数据包示例-电脑资料.docxpython基础教程之获取本机ip数据包示例-电脑资料....
3.4.4 数据包彩亮 - Wireshark 数据包分析实战(第 3 版) - 知乎书店 3.1Wireshark简史 3.3安装Wireshark
通过介绍TCP连接的建立过程(通常称作三阶段握手),进而展开讲述TCP连接的建立与终止的过程,并通过对实验数据编写程序分析截获的一个客户端预多个WEB服务器之间的通信数据包,以得到TCP包的内部连接情况,持续时间...
网络数据包监控程序-课程设计(含课程报告和代码)
B.2 使数据包结构图 - Wireshark 数据包分析实战(第 3 版) - 知乎书店B.2 使数据包结构图我们在第1章中学习到,数据包是按照协议规定的
python基础教程之获取本机ip数据包示例-电脑资料.pdfpython基础教程之获取本机ip数据包示例-电脑资料.pdfpython基础教程之获取本机ip数据包示例-电脑资料.pdfpython基础教程之获取本机ip数据包示例-电脑资料.pdf...
通过介绍TCP连接的建立过程(通常称作三阶段握手),进而展开讲述TCP连接的建立与终止的过程,并通过对实验数据编写程序分析截获的一个客户端预多个WEB服务器之间的通信数据包,以得到TCP包的内部连接情况,持续时间...
udp数据包转发器,能通过局域网,设定IP端口号,来转发数据包
可实现根据手机号获取省,市,运营商,邮政编码,区号信息
从指定网卡上读取数据包,如果读取数据包没有问题,则 pkt_header 参数指向的指针将设置为指向数据包的pcap_pkthdr结构,pkt_data参数指向的指针将设置为指向数据包中的数据
mysql数据库驱动包,Java连接MySQL数据库所需的数据包
7.4.1 Packet Tracer - Implement DHCPv4 Cisco Packet Tracer 思科模拟器 正确答案文件 由于程序问题无法保存激活DHCP端口配置 另加满分步骤截图 可直接上交正确答案文件 本答案版权归mewhaku所有,严禁再次...
声明提要书的赞誉么购买本书与法使本书例捕获件科技基会与持章数据包分析技术与络基础1.1数据包分析与数据包嗅探器1.1.1评估数据包嗅探器1.1.2数据包