2016-01-11 3 views
0

Я хочу реализовать простой сервер, который может получать объект от клиента. Объект, который отправляется клиентом, является подклассом объекта, который принимается (отбрасывается) со стороны сервера.Отправка объекта от клиента на сервер

EDIT: Если я использую тот же подкласс «TestMessage», правильная строка печатается на стороне сервера. Если я использую суперкласс «Сообщение» (я хочу сделать это, потому что мне нужно несколько подклассов сообщений) Строка просто равна нулю. Итак, существует ли определенное свойство ObjectInputStream, которое испортит мои поля или весь объект, если я перейду к суперклассу?

Payload on client side: Hello Server! 
Payload on server side: null 

Я создал абстрактный класс Message, из которого несколько подклассов могут быть получены:

public abstract class Message implements Serializable { 

    private static Random random = new Random(); 

    /** 
    * A 16-byte string (GUID) uniquely identifying the message on the network. 
    */ 
    private byte[] guid; 

    /** 
    * Indicates the type of message. 
    */ 
    private byte messageType; 

    /** 
    * The actual content of the message. 
    */ 
    private static String payload; 

    /** 
    * TODO change to protected? 
    * @return payload 
    */ 
    public static String getPayload() { 
     return payload; 
    } 

    /** 
    * TODO change to protected? 
    * @param payload 
    */ 
    public static void setPayload(String payload) { 
     payload = payload; 
    } 

    /** 
    * @return guid 
    */ 
    public byte[] getGuid() { 
     return guid; 
    } 

    /** 
    * @return messageType 
    */ 
    public byte getMessageType() { 
     return messageType; 
    } 

    /** 
    * Constructor for a newly created message 
    * @param messageType 
    */ 
    public Message(byte messageType) { 
     guid = new byte[16]; 
     random.nextBytes(guid); 

     //TODO encrypt guid? 

     this.messageType = messageType; 
    } 

    /** 
    * Constructor for a received message 
    * @param guid 
    * @param messageType 
    */ 
    public Message(byte[] guid, byte messageType) { 
     this(messageType); 
     this.guid = guid; 
    } 
} 

Теперь, я вывел тип TestMessage тестовое сообщение, которое посылается от клиента к серверу ,

public class TestMessage extends Message { 

    private static byte TYPE_ID = (byte) 0x00; 

    /** 
    * @param payload 
    */ 
    public TestMessage(String payload) { 
     super(TYPE_ID); 

     /** 
     * TODO: Better practice to create a protected setter? 
     */ 
     Message.setPayload(payload); 
    } 
} 

Теперь сервер ничего особенного. Он ожидает, что клиент подключится и прочитает объект Message из потока. Здесь я получаю исключение ClassNotFoundException. Я полагаю, что класс Server не знает класс Message? Почему так? Это проблема, что клиент отправляет подкласс класса, который читает сервер? Или что-то не так с кастингом моего класса Message?

public class TestServer { 

    public static void main(String[] args) throws IOException { 

     int port = 9999; 

     ServerSocket serverSocket = new ServerSocket(port); 
     Socket socket = serverSocket.accept(); 

     InputStream inputStream = socket.getInputStream(); 
     ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); 

     Message incomingMessage = null; 
     incomingMessage = (Message)objectInputStream.readObject(); 

     System.out.println("Payload: " + Message.getPayload()); 
    } 

}

И, наконец, клиент:

public class TestClient { 

    public static void main(String[] args) throws IOException { 

     String serverAdress = "localhost"; 
     int port = 9999; 

     Socket socket = new Socket(serverAdress, port); 

     OutputStream outputStream = socket.getOutputStream(); 
     ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); 

     TestMessage testMessage = new TestMessage("Hello Server!"); 

     objectOutputStream.writeObject(testMessage); 
    } 
} 

Спасибо, ребята заранее! Я надеюсь, что кто-то может мне помочь.

+1

Вы должны предоставить полную трассировку стека вместо полного кода. По крайней мере, длинный код интерфейса здесь не нужен. –

+1

Являются ли классы 'Message' end' TestMessage' доступными в пути к классам серверов? – toKrause

+0

Каждый класс находится в одном пакете, поэтому я думал, что этого будет достаточно. Вы хотите объяснить, как добавить их в classpath? Спасибо! – Ipsider

ответ

2

Причина вы получаете null это:

public static void setPayload(String payload) { 
     payload = payload; 
    } 

знать о пространствах имен. Этот метод присваивает параметр самому себе, а затем, в конечном итоге, объект уничтожается. Если вы хотите назначить параметр статическому члену, вы должны его правильно адресовать, используя Message.payload. Но в этом случае использование статического члена - не очень хорошая идея.

Это было бы лучше, потому что вы хотите отменить/сериализовать объект (не класс):

private String payload; 

public String getPayload() { 
    return payload; 
} 
public void setPayload(String payload) { 
    this.payload = payload; 
} 

Убедитесь, чтобы изменить метод вызывает в TestClient/TestServer соответственно.

Окончательный совет: если вы не закрываете сокеты в TestClient/TestServer, вы можете в конечном итоге с java.net.SocketException s при запуске обоих классов более одного раза (в зависимости от вашей операционной системы).

+0

есть. Я должен быть более осторожным. Спасибо! – Ipsider

3

На принимающей стороне вашего приложения вы не имеет класс, определяющий ваш объект поэтому не представляется возможным десериализации его и построить экземпляр.

Этот класс должен присутствовать в обеих сторонах (клиент и сервер).

Проверьте свой класс, чтобы узнать, присутствует ли этот класс или нет. В итоге добавьте правильную банку (или .class).

+0

классы клиентов, серверов и сообщений находятся в одном пакете. Я думал, этого будет достаточно. Можете ли вы дать мне понять, как добавить класс в classpath другого класса? – Ipsider

+1

Не добавляйте класс в classpath другого класса, но добавьте класс к пути к классам JVM, на котором запущен ваш основной. Самое простое решение - добавить этот класс к обоим проектам. Otherwyse добавьте его как параметр в команду запуска java: java -classpath C: \ java \ MyClasses utility.myapp.Cool –

1

Реализация класса Message необходима на стороне сервера для объекта, отправленного клиентом для десериализации на сервере. Под этим я подразумеваю classpath сервера jvm (основной класс TestServer), который должен содержать банку, которая содержит байт-код для класса Message.

+0

Хорошо. Это всего лишь тестовая архитектура, поэтому каждый класс находится в одном проекте и в том же пакете. Я думал, этого будет достаточно. Не волнуйтесь, как добавить класс Message в classpath класса сервера? Если я посмотрю на источники проекта в Eclipse, все включено:/ – Ipsider

+1

как вы используете сервер и классы клиентов? –

+1

Способ внедрения сервера и классов клиентов через IntelliJ Idea IDE. Я попытался продемонстрировать то же самое и из командной строки, просто для того, чтобы исключить проблемы, связанные с IDE. –

Смежные вопросы