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

编辑:如果我使用相同的子类“ TestMessage”,则在服务器端将打印正确的字符串。如果使用超类“消息”(我想这样做,因为我需要多个消息子类),则该字符串仅为null。那么,是否存在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。我想服务器类不知道消息类?为什么这样?客户端发送服务器读取的类的子类是否有问题?还是我的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);
    }
}


预先谢谢你们!我希望有一个人可以帮助我。

最佳答案

您得到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结尾。

10-07 19:10
查看更多