使用ObjectInputStream与ObjectOutputStream做转发时遇到的序列化问题

时间:2020-8-29 作者:admin


Warning:并没有解决问题,只是换了条路

0. 陈述流程

使用ObjectInputStream与ObjectOutputStream做转发时遇到的序列化问题
首先A和C是客户端,B是服务器,A发送内容B接收内容后对内容修改并转发到C,其实代码是双向的,这里简化一下,只让A发送
发送的消息是ClientMsg对象,对象内有int和String还有对象people,people对象内有int和String。
B需要修改的内容只是people,其他不做修改

ClientMsg类(没在图上的的是get和set方法)

使用ObjectInputStream与ObjectOutputStream做转发时遇到的序列化问题

people类

使用ObjectInputStream与ObjectOutputStream做转发时遇到的序列化问题

服务器的修改并转发

使用ObjectInputStream与ObjectOutputStream做转发时遇到的序列化问题

1. 遇到问题

A发送消息后由B接收,此时没有问题,B接收后对接收的ClientMsg对象内部的people对象修改,修改后客户端接收到的却是修改之前的内容

2.排查问题

在服务端接收到消息后和转发消息后打印消息,显示的是已经修改,并且在删除掉people对象的toString方法后打印的内存地址值也是已经修改的,但是接收端接收的却是修改前的消息,试着修改一下写法:
原来:直接修改people对象,然后把people对象放入ClientMsg对象
修改后:修改ClientMsg对象内部people对象的Id
发现修改后的写法可以了

3.问题原因

这个在我写这个博客的时候我还不太清楚,问了问认识的大手子,他说是因为序列化和反序列化的原因

4.解决办法

不用ObjectInputStream与ObjectOutputStream,改用JSON,而且JSON的序列化效率还比java快,
这条路难走就走另一条路,更何况另一条路还更好(滑稽)
下边的链接是JSON和ObjectOutputStream速度比较的一个博客

Java ObjectOutputStream序列化与JSON序列化大比拼

4.代码

Server.java
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;

public class Server {
    // 分配给socket连接的id,用于区分不同的socket连接
    private static int id = 0;
    private static int now = 0;
    // 存储socket连接,发送消息的时候从这里取出对应的socket连接
    private static HashMap<Integer, ServerThread> socketList = new HashMap<>();
    private ServerSocket server;
    private static people people;
    private static people people1;

    /**
     * 构造函数,输入端口号
     */
    public Server(int port) {
        people = new people(911, "如果看到这句话就是直接修改CilentMsg的对象");
        people1 = new people(999, "如果看到这句话就是修改CilentMsg的people的name");
        try {
            this.server = new ServerSocket(port);
            System.out.println("服务器启动完成 使用端口: " + port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void start() {
        try {
            while (true) {
                Socket socket = server.accept();
                System.out.println(++id + ":客户端接入:" + socket.getInetAddress() + ":" + socket.getPort());
                ServerThread thread = new ServerThread(id, socket);
                socketList.put(id, thread);
                thread.run();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 服务线程,当收到一个TCP连接请求时新建一个服务线程
    private class ServerThread implements Runnable {
        private int id;
        private Socket socket;
        private InputStream in;
        private OutputStream out;
        private ObjectInputStream oin;
        private ObjectOutputStream oot;

        ServerThread(int id, Socket socket) {
            try {
                this.id = id;
                this.socket = socket;
                this.in = socket.getInputStream();
                this.out = socket.getOutputStream();
                this.oin = new ObjectInputStream(in);
                this.oot = new ObjectOutputStream(out);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        /**
         * 新开线程进行读操作
         */
        @Override
        public void run() {
            new Reader().start();
        }

        /**
         * 因为同时只能有一个键盘输入,所以输入交给服务器管理而不是服务线程
         * 服务器负责选择socket连接和发送的消息内容,然后调用服务线程的write方法发送数据
         */
        public void send(ClientMsg data) {
            if (!socket.isClosed() && data != null) {
                try {
                    oot.writeObject(data);
                    oot.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        /**
         * 关闭所有资源
         */
        public void close() {
            try {
                if (oin != null)
                    oin.close();
                if (oot != null)
                    oot.close();
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.close();
                }
                if (socket != null) {
                    socket.close();
                }
                socketList.remove(id);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        private class Reader extends Thread {
            @Override
            public void run() {
                try {
                    ClientMsg clientMsg;
                    while (!socket.isClosed()) {
                        clientMsg = (ClientMsg) oin.readObject();
                        System.out.println(id + ":接受到的Msg:\n " + clientMsg);
                        people.setAge(now);
                        people1.setAge(now);
                       /* clientMsg.setPeople(people1);
                        System.out.println("修改后的ClientMsg对象\n" + clientMsg);
                        now++;
                        //转发
                        if (socketList.size() > 1)
                            socketList.get(id == 1 ? 2 : 1).send(clientMsg);*/
                        if (clientMsg.getId() == 8) {
                            clientMsg.setPeople(people1);
                            System.out.println("直接修改对象内的people");
                        } else {
                            clientMsg.getPeople().setAge(now);
                            System.out.println("修改信息对象内people的id");
                        }
                        System.out.println("修改后的ClientMsg对象\n" + clientMsg);
                        System.out.println("now" + now);
                        now++;
                        //转发
                        if (socketList.size() > 1)
                            socketList.get(id == 1 ? 2 : 1).send(clientMsg);
                    }
                    // 如果循环中断说明连接已断开
                    System.out.println(id + ":客户端主动断开连接");
                    close();
                } catch (IOException | ClassNotFoundException e) {
                    System.out.println(id + ":连接已断开");
                } finally {
                    close();
                }
            }

            private int numUP(int num) {
                return (num++);
            }
        }

    }

    public static void main(String[] args) {
        new Server(8080).start();
    }
}
Client.java
import java.io.*;
import java.net.Socket;
import java.util.ArrayList;

/**
 * 客户端 全双工 但同时只能连接一台服务器
 */
public class Client {
    private Socket socket;
    private InputStream in;
    private OutputStream out;
    private static ObjectInputStream oin;
    private static ObjectOutputStream oot;

    /**
     * 启动客户端需要指定地址和端口号
     */
    private Client(String address, int port) {
        try {
            socket = new Socket(address, port);
            in = socket.getInputStream();
            out = socket.getOutputStream();
            oot = new ObjectOutputStream(out);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("客户端启动成功");
    }

    public void start() {
        // 和服务器不一样,客户端只有一条连接,能省很多事
        Reader reader = new Reader();
        Writer writer = new Writer();
        reader.start();
        writer.start();
    }

    public void close() {
        try {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
            if (socket != null) {
                socket.close();
            }
            System.exit(0);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private class Reader extends Thread {
        public Reader() {

        }

        @Override
        public void run() {
            try {
                ClientMsg clientMsg;
                if (oin == null)
                    oin = new ObjectInputStream(in);
                System.out.println("输入a,Msg的Id为8,服务端会直接修改Msg的people对象\n输入不是a,msg的Id为9,服务端会修改Msg的people对象的id");
                while (!socket.isClosed()) {
                    clientMsg = (ClientMsg) oin.readObject();
                    System.out.println("Server\n" + clientMsg);
                }
                System.out.println("服务器主动断开连接");
                close();
            } catch (ClassNotFoundException | IOException e) {
                System.out.println("连接已断开");
            } finally {
                close();
            }
        }
    }

    private class Writer extends Thread {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        @Override
        public void run() {
            try {
                String line = "";
                while (!socket.isClosed() && line != null && !"exit".equals(line)) {
                    line = reader.readLine();
                    //数据只是随便写的,主要是为了测试
                    if ("a".equals(line)) {
                        oot.writeObject(new ClientMsg(8, line, new people(0, "是A")));
                    } else {
                        oot.writeObject(new ClientMsg(9, line, new people(0, "不是A")));
                    }
                }
                System.out.println("客户端退出");
                close();
            } catch (IOException e) {
                System.out.println("error:连接已关闭");
            } finally {
                close();
            }
        }
    }

    public static void main(String[] args) {
//        String address = args[0];
//        int port = Integer.parseInt(args[1]);
//        new Client(address, port).start();
        new Client("127.0.0.1", 8080).start();
    }
}
people.java
import java.io.Serializable;
import java.util.ArrayList;

public class people implements Serializable {
    private int age;
    private String name;

    public people(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

//    @Override
//    public String toString() {
//        return "people{" +
//                "age=" + age +
//                ", name='" + name + '\'' +
//                '}';
//    }

}

ClientMsg.java

import java.io.Serializable;

public class ClientMsg implements Serializable {
    private int id;
    private String msg;
    private people people;

    public ClientMsg(int id, String msg, people people) {
        this.id = id;
        this.msg = msg;
        this.people = people;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public people getPeople() {
        return people;
    }

    public void setPeople(people people) {
        this.people = people;
    }

    @Override
    public String toString() {
        return "ClientMsg{" +
                "id=" + id +
                ", msg='" + msg + '\'' +
                ", people=" + people +
                '}';
    }
}

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。