【问题标题】:Object recieved by ObjectInputStream not equal to Object sent by ObjectOutputStreamObjectInputStream 收到的对象不等于 ObjectOutputStream 发送的对象
【发布时间】:2018-04-12 15:53:21
【问题描述】:

我正在开发一个在 Java 中执行对象 IO 的项目。问题出在Client和Server之间的关系上,位于Server中的ObjectOutputStream发送的对象不等于Client收到的类。

此处编写的 ClientLoop 类在客户端上不存在。(我可能应该更改它以避免混淆。)为每个客户端创建一个 ClientLoop,来自一个 Socket,它被检测到并且是从服务器建立连接。它侦听客户端发送的下一个对象,并将其发送到对象管道,在此确定操作。

A question possibly anticipating the underlying technology from the object streams

public class ClientLoop extends Loop implements Sendable {
    private final Commander commander;

    private final Socket socket;
    private final ObjectInputStream input;
    private final ObjectOutputStream output;
    private final Server server;

    public ClientLoop(Server server, Socket socket) throws IOException {
        this.server = server;
        this.socket = socket;

        //we need to construct the output stream first
        //to discard the stream header
        this.output = new ObjectOutputStream(socket.getOutputStream());
        this.input = new ObjectInputStream(socket.getInputStream());

        this.commander = new Commander(server, socket, this);
    }

    @Override
    public void loop() {
        try {
            try {
                Object next = input.readObject();
                String className = next.getClass().getName();

                System.out.println("Server Receive: " + next);

                if (className.equals("com.meti.server.util.Command")) {
                    commander.runCommand(castIfOfInstance(next, Command.class));
                //this section of code here says that whenever an AssetChange is being sent by the client. 
                } else if (next instanceof AssetChange) {
                    AssetChange assetChange = castIfOfInstance(next, AssetChange.class);
                    assetChange.update(server.getAssetManager().getAsset(assetChange.getAssetPath()));

                    //has been change, update all clientloops
                } else {
                    getInstance().log(Level.WARNING, "Found no type handling " +
                            "for class type " + className);
                }
            } catch (EOFException e) {
                socket.close();
                setRunning(false);
            }
        } catch (Exception e) {
            getInstance().log(Level.WARNING, e);
        }
    }

    @Override
    public void send(Serializable serializable, boolean flush) throws IOException {
        System.out.println("Server Send: " + serializable);

        output.writeObject(serializable);
        if (flush) {
            output.flush();
        }
    }
}

Commander 类在这里提供了 ClientLoop 类的附加功能,而在该类中该类太难理解了。它仅用于容纳运行命令的方法。它可能不是最好的代码结构,稍后会修复它。

public class Commander {
    private Server server;
    private Socket socket;
    private Sendable sendable;

    public Commander() {
    }

    public Commander(Server server, Socket socket, Sendable sendable) {
        this.server = server;
        this.socket = socket;
        this.sendable = sendable;
    }

    public void runCommand(Command next) throws IOException {
        if ("login".equals(next.getName())) {
            String password = (String) next.getArgs()[0];
            if (password.equals(server.getPassword())) {
                getInstance().log(Level.INFO, "Client " + socket.getInetAddress() + " has connected with valid password");
            } else {
                getInstance().log(Level.INFO, "Client has invalid password, kicking out!");
                socket.close();
            }
        } else if ("disconnect".equals(next.getName())) {
            socket.close();
        } else if ("list".equals(next.getName())) {
            Cargo<String> cargo = new Cargo<>();
            HashMap<String, Asset<?>> assets = server.getAssetManager().getAssets();
            ArrayList<String> paths = new ArrayList<>();
            paths.addAll(assets.keySet());
            cargo.getContents().addAll(paths);

            sendable.send(cargo, true);

        } else if ("get".equals(next.getName())) {//should be declared other side...
            String path = Utility.castIfOfInstance(next.getArgs()[0], String.class);
            Asset<?> asset = server.getAssetManager().getAsset(path);

            sendable.send(asset, true);
        }
    }
}

这是最新运行会话的日志。每当它说“Server Receive”时,就意味着服务器找到了客户端发送的对象,当它说“Server Send”时,它将是服务器通过 ObjectInputStream 和 ObjectOutputStream 发送的对象。否则,它是一个通用的控制台语句。在日志的最后,它显示服务器发送了一个名为 “服务器发送:资产{file=Nexus\sample.txt,内容=Hello Server!asdxc}”。 (请注意,“asdxc”这个短语是在测试期间使用按钮混搭创建的。它不包含任何代码意义。)

然而,问题就出在这里,在前面的陈述中 “接收:Asset{file=Nexus\sample.txt, content=Hello Server!}”。

我从这个日志输出中得出结论,客户端中的 ObjectInputStream 和服务器中的 ObjectOutputStream 确实运行正常,但是 服务器上的 ObjectOutputStream 发送的对象不等于 ObjectInputStream 立即接收的对象在客户端。根据日志,服务器发送的只有一个对象,客户端没有正确注册。

Oct 31, 2017 8:11:11 AM com.meti.Main log
INFO: Starting application
Oct 31, 2017 8:11:50 AM com.meti.Main log
INFO: Reading directory
Oct 31, 2017 8:11:51 AM com.meti.Main log
INFO: Listening for clients
Oct 31, 2017 8:11:53 AM com.meti.Main log
INFO: Located client at /127.0.0.1
Server Receive: Command{name='login', args=[5875580034436271440]}
Oct 31, 2017 8:11:53 AM com.meti.Main log
INFO: Client /127.0.0.1 has connected with valid password
Server Receive: Command{name='list', args=[files]}
Server Send:com.meti.server.util.Cargo@68917144
Server Receive: Command{name='get', args=[Nexus\sample.txt]}
Server Send:Asset{file=Nexus\sample.txt, content=Hello Server!}
Receive: Asset{file=Nexus\sample.txt, content=Hello Server!}
Server Receive: com.meti.server.asset.text.TextChange@546c91cb
Server Receive: com.meti.server.asset.text.TextChange@1a2f571d
Server Receive: com.meti.server.asset.text.TextChange@7a308ae0
Server Receive: com.meti.server.asset.text.TextChange@5897f82d
Server Receive: com.meti.server.asset.text.TextChange@68c5d83d
Server Receive: com.meti.server.asset.text.TextChange@832ed87
Server Receive: com.meti.server.asset.text.TextChange@76ab11eb
Server Receive: Command{name='get', args=[Nexus\sample.txt]}
Server Send:Asset{file=Nexus\sample.txt, content=Hello Server!asdxc}
Receive: Asset{file=Nexus\sample.txt, content=Hello Server!}

如果需要更多代码来诊断问题,我在这个 GitHub 链接上有完整的代码库: https://github.com/Mathhman/Nexus

【问题讨论】:

  • 你能创建一小段代码来重现错误吗?

标签: java sockets objectinputstream objectoutputstream


【解决方案1】:

如果您两次发送具有不同内容的同一个对象,您需要使用writeUnshared()reset() 以确保它实际上被再次发送。

【讨论】:

    猜你喜欢
    • 2018-11-06
    • 1970-01-01
    • 2013-07-13
    • 2012-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-13
    相关资源
    最近更新 更多