2016-01-11 118 views
0

我想实现一个简单的服务器,它能够从客户端接收一个对象。从客户端发送的对象是在服务器端接收(投射)的对象的子类。从客户端发送一个对象到服务器

编辑:如果我使用相同的子类“TestMessage”正确的字符串打印在服务器端。如果我使用超类“消息”(我想这样做,因为我需要多个消息子类)字符串只是空。那么是否存在ObjectInputStream的特定属性,如果我将其投影到超类,它会弄乱我的字段或整个对象?

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

我已经创建了一个抽象类消息,从该几个子类可以导出:

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。我想服务器类不知道消息类?为什么这样?客户端发送服务器读取的类的子类是否存在问题?或者我的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'结尾的'TestMessage'类可用? – toKrause

+0

每个班级都在同一个包中,所以我认为这就够了。你是否在意解释如何将它们添加到类路径中?谢谢! – Ipsider

回答

2

您得到null原因是这样的:

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

注意命名空间。该方法为自身分配一个参数,然后最终该对象被销毁。如果要将参数分配给静态成员,则必须使用Message.payload正确地对其进行处理。但在这种情况下,使用静态成员不是一个好主意。

这将是更好的,因为你要DE /序列化对象(不是一类):

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

在您的应用程序接收端还没有定义你的对象类,因此无法反序列化,并建立了实例。

该类必须存在于双方(客户端和服务器)中。

检查您的类路径以查看该类是否存在。最终添加正确的jar(或.class)。

+0

客户端,服务器和消息类都在同一个包中。我认为这就够了。你能否给我提示如何将类添加到另一个类的类路径中? – Ipsider

+1

不向另一个类的类路径添加类,但将类添加到运行main的JVM的类路径中。最简单的解决方案是将这个类添加到这两个项目。 Otherwyse将其作为参数添加到java启动命令中:java -classpath C:\ java \ MyClasses utility.myapp.Cool –

1

在服务器端需要Message类实现,以便客户端发送的对象在服务器上反序列化。由此,我的意思是服务器jvm(TestServer主类)的类路径应该包含包含类Message的字节码的jar。

+0

好的。这只是一个测试架构,所以每个类都在同一个项目和相同的包中。我认为这就够了。您是否在意详细说明如何将Message类添加到服务器类的类路径中?如果我在Eclipse中查看项目的源代码,则包含所有内容:/ – Ipsider

+1

您如何运行服务器和客户端类? –

+1

运行服务器和客户端类的方式是通过IntelliJ IDE IDE。我试图从命令行演示相同的东西,只是为了让IDE相关的问题不在图片中。 –

相关问题