java - 通过可序列化的套接字传输对象

标签 java sockets serialization

这是我编写的代码,用于通过套接字传输对象 pm(属于 PM 类),其中包含任何对象 vm(属于 VM 类)。

public class PM implements Serializable{
    private static final long serialVersionUID=1L;

    VM vm[]=new VM[10];

    //IP of the Agent
    String IP;

    public PM() {
        super();
        for(int i=0;i<10;i++){
            vm[i]=new VM();}
        }
    }

VM 是另一个类,它有自己的属性。

public class VM implements Serializable{
       String osType;
}

对象 pm 通过套接字的交换发生在 2 台 PC 之间。服务器端在服务器执行网络发现(因此类名)后从客户端接收对象。

public class NetworkDiscovery extends TimerTask {
    InetAddress controllerIP;
    int controllerPort;
    static PM pm = new PM();

    NetworkDiscovery() throws UnknownHostException {
        controllerIP=InetAddress.getLocalHost();
        controllerPort=4455;
    }
    public void run() {
        try {
            byte[] recvBuf = new byte[5000];
            DatagramPacket packet = new DatagramPacket(recvBuf, recvBuf.length);
            DatagramSocket dSock = new DatagramSocket(4445);
            dSock.receive(packet);
            int byteCount = packet.getLength();
            ByteArrayInputStream byteStream = new ByteArrayInputStream(recvBuf);
            ObjectInputStream is = new ObjectInputStream(new BufferedInputStream(byteStream));
            pm=(PM)is.readObject();
            System.out.println("object1" +pm.IP);
            is.close();
            dSock.close();
            System.out.println("object" + pm.vm[0].vmName);
        } //exceptions are caught etc.
    }
}

并且在发送 pm 对象到服务器的客户端:

public class ackDiscovery extends TimerTask{
    int agentListenPort;
    InetAddress agentIP;
    ackDiscovery(Connect c) {
        agentListenPort=4445;
        c1=c;
    }
    public void run() {
        ObjectOutputStream os = null;
        try {
            PM pm = new PM();
            {
                pm.IP = InetAddress.getLocalHost().toString();
                pm.vm[i].osType = d1.getOSType();
                System.out.println("VMname" +i +pm.vm[i].osType);
                pm.vm[i].status = d1.isActive();
            }
            InetAddress address = InetAddress.getByName("Server_IP");
            ByteArrayOutputStream byteStream = new ByteArrayOutputStream(15000);
            os = new ObjectOutputStream(new BufferedOutputStream(byteStream));
            os.flush();
            os.writeObject((PM) pm);
            os.flush();
            byte[] sendBuf = byteStream.toByteArray();
            DatagramPacket packet = new DatagramPacket(sendBuf, sendBuf.length, address, 4445);
            int byteCount = packet.getLength();
            DatagramSocket dSock = new DatagramSocket();
            System.out.println("Quote of the Moment: " + pm.vm[0].osType);
            dSock.send(packet);
            os.close();
            dSock.close();
        } //exceptions caught etc.
    }
}

所有 vm 和 pm 详细信息都在客户端填充(我已经通过打印它们进行了检查)。在服务器端,传输后只有 pm 详细信息会填充到本地 pm 对象中。在服务器端显示虚拟机详细信息会给我空值。

我的疑问:

  1. 不是也传一个有子对象的对象,是不是整个父+子对象都传了?
  2. 我是否必须分别手动传输 vm 和 pm 对象?

编辑-

public class VM implements Serializable{
       String osType,vmName; //on server's side, these are still null
       int UUID,osVersion;   // on the server's side, these are 0. Are integer variables initialised to a default of zero?
       }

最佳答案

正如@Hovercraft... 提到的,是的,如果字段标记为transient,则VM 也应该被序列化。 transient ( definition ) 是 Java 关键字,表示序列化应忽略该字段。如果 vm 字段被标记为 transient,那么它将始终作为 null 到达接收方。在您的情况下,vm 字段应该使用 transient 关键字。

不确定问题出在哪里,但我想对一些事情发表评论。

  • 是否有可能您在不同的 PC 上安装了不同版本的软件?接收方是否肯定在 PM 中有 vm 字段?
  • 最好在每次更改类时增加您的 Serializable id,以确保 PM 类在客户端和服务器上匹配。您还可以删除 serialVersionUID 并让 VM 生成一个确保您在两侧都有匹配的类。如果它们不匹配,这将给出一个异常(exception)。
  • 您可能知道这一点,但请注意 PM 大小不要超过数据包大小,因为您正在使用 DatagramPacket。它们可以被分割、重新排序、根本不交付等等。我怀疑 ObjectInputStream 会给你一个部分对象。
  • 确保捕获异常并正确记录相关消息,尽管如果它被抛出,您将不会得到任何对象。

为了后代,建议生成一个 serialVersionUID 而不是依赖 VM 的运行时计算。更改对象时是否更改 ID 取决于您正在实现的分布式系统类型。

顺便说一句,serialVersionUID 是一个类标识符,它帮助 Java VM 验证被序列化的类是否与被反序列化的类的定义相匹配。当对象被反序列化时,VM 会查找对象的类并确保 UID 相同。如果不是,则在反序列化对象时抛出 InvalidClassException 异常。 2 个不同的类是否具有相同的 UID 并不重要。

希望这对您有所帮助。

关于java - 通过可序列化的套接字传输对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7784072/

相关文章:

java - 如何使用 java servlet 和 HttpURLConnection 对文件传输进行校验和

java - Java 静态方法可以可视化为 python 中的函数 + 具有相同名称(作为函数)的实例方法吗?

java - 无法为某些设备生成 FCM token

Java 1.7.0_u25 小程序用eclipse调试

sockets - Crystal 中套接字处理的 Spawn 与 Select

json - 如何使用XOJO从Web加载JSON?

java - 我设法保存,但没有加载(序列化)

c - 在 C 中同时执行两个本地套接字服务器

java - Protobuf - 序列化和反序列化中参数的不同命名

java - 将可序列化对象作为参数传递时出现 GWT SerializationException