Передача объекта через сокеты-сериализуемый - PullRequest
1 голос
/ 16 октября 2011

Это код, который я написал для передачи объекта 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 через сокеты происходит между двумя компьютерами. Серверная сторона получает объект со стороны клиента после того, как сервер выполнил обнаружение сети (отсюда и имена классов).

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 после передачи. отображение подробностей vm на стороне сервера дает мне нулевые значения.

Мои сомнения:

  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?
       }

Ответы [ 2 ]

2 голосов
/ 16 октября 2011

Как упоминалось @Hovercraft ... да, VM также следует сериализовать, если поле не помечено transient.transient ( определение ) - это ключевое слово Java, которое говорит, что сериализация должна игнорировать это поле.Если поле vm помечено как transient, оно всегда будет поступать как null на приемнике.В вашем случае поле vm должно , а не использовать ключевое слово transient.

Не знаю, в чем проблема, но некоторые вещи, которые я решил прокомментировать.

  • Возможно ли, что на разных ПК установлена ​​другая версия программного обеспечения?Есть ли у получателя поле vm в PM наверняка?
  • Возможно, будет полезно увеличивать ваш Serializable идентификатор каждый раз, когда вы меняете класс, чтобы убедиться, что класс PM соответствует клиентуи сервер.Вы также можете удалить serialVersionUID и позволить сгенерированной виртуальной машине убедиться, что у вас совпадающий класс с обеих сторон.Это даст исключение, если они не совпадают.
  • Вы, вероятно, знаете это, но будьте осторожны, чтобы размер PM не превышал размер пакета, так как вы используете DatagramPacket.Они могут быть фрагментированы, переупорядочены, вообще не доставлены и т. Д. Я сомневаюсь, что ObjectInputStream даст вам частичный объект.
  • Убедитесь, что вы ловите исключения и правильно регистрируете связанные сообщения, хотя вы не получите любых объектов, если он выбрасывает.

Только для потомков, этоРекомендуется генерировать serialVersionUID вместо того, чтобы полагаться на вычисления времени выполнения виртуальной машины.Изменение или отсутствие изменения идентификатора при изменении объекта зависит от того, какую распределенную систему вы реализуете.

Кстати, serialVersionUID - это идентификатор для каждого класса, который помогает виртуальной машине Java проверить, что классэто было сериализовано, соответствует определению десериализованного класса.Когда объект десериализуется, виртуальная машина ищет класс объекта и проверяет, совпадает ли UID.Если нет, то возникает исключение InvalidClassException при десериализации объекта.Не имеет значения, если 2 разных класса имеют одинаковый UID.

Надеюсь, это поможет.

1 голос
/ 06 августа 2013

Массивы являются первоклассными объектами в Java, они не являются сериализуемыми объектами.Существует три основных решения этой проблемы:

Поля могут быть объявлены как переходные.Методы writeObject () / readObject () могут быть реализованы.serialPersistentFields могут быть объявлены.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...