2016-01-11 116 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相關的問題不在圖片中。 –

相關問題