Java 将对象从客户端发送到服务器

Java 将对象从客户端发送到服务器,java,sockets,Java,Sockets,我想实现一个简单的服务器,它能够从客户机接收对象。从客户端发送的对象是在服务器端接收(转换)的对象的子类 编辑:如果我使用相同的子类“TestMessage”,则在服务器端打印正确的字符串。如果我使用超类“Message”(我想这样做,因为我需要多个Message子类),字符串就是null。那么ObjectInputStream是否有一个特定的属性,如果我强制转换到超类,它会弄乱我的字段或整个对象 Payload on client side: Hello Server! Payload on

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

编辑:如果我使用相同的子类“TestMessage”,则在服务器端打印正确的字符串。如果我使用超类“Message”(我想这样做,因为我需要多个Message子类),字符串就是null。那么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);
    }
}
现在服务器没有什么特别的了。它等待客户端连接并从流中读取消息对象。这里我得到一个ClassNotFoundException。我想服务器类不知道消息类?为什么会这样?客户端发送服务器读取的类的子类是否有问题?还是我的消息类的角色设置有问题

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);
    }
}

提前谢谢你们!我希望有人能帮助我。

在应用程序的接收端您的没有定义对象的类,因此无法对其进行反序列化并构建实例

该类必须同时存在于客户端和服务器端


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

在应用程序的接收端您没有定义对象的类,因此无法对其进行反序列化并构建实例

该类必须同时存在于客户端和服务器端


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

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

服务器端需要
消息
类实现,才能在服务器端反序列化从客户端发送的对象。我的意思是,服务器jvm(TestServer主类)的类路径应该包含jar,其中包含类
消息
的字节码

您得到
null
的原因是:

    public static void setPayload(String payload) {
        payload = payload;
    }
注意名称空间。该方法将参数分配给自身,然后最终销毁对象。如果要将参数分配给静态成员,则必须使用
Message.payload
正确地对其进行寻址。但是在这种情况下,使用静态成员不是一个好主意

这会更好,因为您希望反序列化对象(而不是类):

确保相应地更改
TestClient/TestServer
中的方法调用


最后一个提示:如果不关闭
TestClient/TestServer
中的套接字,则在多次运行这两个类(取决于您的操作系统)时,可能会出现
java.net.SocketException
s。

    public static void setPayload(String payload) {
        payload = payload;
    }
注意名称空间。该方法将参数分配给自身,然后最终销毁对象。如果要将参数分配给静态成员,则必须使用
Message.payload
正确地对其进行寻址。但是在这种情况下,使用静态成员不是一个好主意

这会更好,因为您希望反序列化对象(而不是类):

确保相应地更改
TestClient/TestServer
中的方法调用


最后一个提示:如果不关闭
TestClient/TestServer
中的套接字,则在多次运行这两个类(取决于您的操作系统)时,可能会出现
java.net.SocketException
s。

您应该提供完整的堆栈跟踪,而不是完整的代码。至少这里不需要冗长的接口代码。服务器类路径中是否有
Message
end
TestMessage
类?每个类都在同一个包中,所以我认为这就足够了。您想解释一下如何将它们添加到类路径中吗?非常感谢。如何运行TestClient和TestServer。从命令行还是某个IDE?设置类路径在很大程度上取决于此。我从Eclipse开始。整个src文件夹都在类路径中。您应该提供完整的堆栈跟踪,而不是完整的代码。至少这里不需要冗长的接口代码。服务器类路径中是否有
Message
end
TestMessage
类?每个类都在同一个包中,所以我认为这就足够了。您想解释一下如何将它们添加到类路径中吗?非常感谢。如何运行TestClient和TestServer。从命令行还是某个IDE?设置类路径在很大程度上取决于此。我从Eclipse开始。整个src文件夹都在类路径中。客户端、服务器和消息类都在同一个包中。我想那就足够了。你能告诉我如何将类添加到另一个类的类路径中吗?不要将类添加到另一个类的类路径中,而是将类添加到运行主类的JVM的类路径中。最简单的解决方案是将该类添加到两个项目中。其他方法是将其作为参数添加到java启动命令:java-classpath C:\java\MyClasses utility.myapp.cool客户端、服务器和消息类都在同一个包中。我想那就足够了。你能告诉我如何将一个类添加到另一个类的类路径中吗?不要将一个类添加到另一个类的类路径中,而是将一个类添加到另一个类的类路径中