【问题标题】:Simple P2P server, object gets corrupted after being relayed from the server简单的 P2P 服务器,对象在从服务器中继后损坏
【发布时间】:2020-03-09 14:12:01
【问题描述】:

使用

public class Server {
    private static ServerSocket server;
    private static int port = 9876;
    private static Socket p1 = null;
    private static Socket p2 = null;

    public static void main(String args[]) {
        System.out.println("[Server] Attempting to bind port " + port);
        try {
            server = new ServerSocket(port);
        } catch (IOException err) {
            err.printStackTrace();
            System.exit(1);
        }
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(p1 == null) {
                    try {
                        System.out.println("[Server] Waiting for P1 to connect");
                        p1 = server.accept();
                        System.out.println("[Server] P1 has connected");
                        ObjectInputStream ois = new ObjectInputStream(p1.getInputStream());
                        ObjectOutputStream oos = new ObjectOutputStream(p1.getOutputStream());
                        while (p1.isConnected()) {
                            String message = (String) ois.readObject();
                            System.out.println("[Server] P1 sent '" + message + "'");
                            if (p2.isConnected()) {
                                ObjectOutputStream p2out = new ObjectOutputStream(p2.getOutputStream());
                                p2out.writeObject("[P1] " + message);
                            } else {
                                oos.writeObject("[Server] P2 is not connected");
                            }
                        }
                        System.out.println("[Server] P1 has disconnected");
                        p1 = null;
                    } catch (Exception err) {
                        if(err instanceof SocketException) {
                            System.out.println("[Server] P1 has disconnected");
                            p1 = null;
                        } else {
                            err.printStackTrace();
                        }
                    }
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(p2 == null) {
                    if(p1 != null) {
                        try {
                            System.out.println("[Server] Waiting for P2 to connect");
                            p2 = server.accept();
                            System.out.println("[Server] P2 has connected");
                            ObjectInputStream ois = new ObjectInputStream(p2.getInputStream());
                            ObjectOutputStream oos = new ObjectOutputStream(p2.getOutputStream());
                            while (p2.isConnected()) {
                                String message = (String) ois.readObject();
                                System.out.println("[Server] P2 sent '" + message + "'");
                                if (p1.isConnected()) {
                                    ObjectOutputStream p1out = new ObjectOutputStream(p1.getOutputStream());
                                    p1out.writeObject("[P2] " + message);
                                } else {
                                    oos.writeObject("[Server] P1 is not connected");
                                }
                            }
                            System.out.println("[Server] P2 has disconnected");
                            p2 = null;
                        } catch (Exception err) {
                            if(err instanceof SocketException) {
                                System.out.println("[Server] P2 has disconnected");
                                p2 = null;
                            } else {
                                err.printStackTrace();
                            }
                        }
                    }
                }
            }
        }).start();
    }

}

public class Client {
    static ObjectOutputStream oos = null;
    static ObjectInputStream ois = null;
    static int port = 9876;
    public static void main(String[] args) throws UnknownHostException, IOException, ClassNotFoundException, InterruptedException{
        InetAddress host = InetAddress.getLocalHost();
        Socket socket = new Socket(host.getHostName(), port);
        System.out.println("[Client] Connection established with port " + port);
        oos = new ObjectOutputStream(socket.getOutputStream());
        ois = new ObjectInputStream(socket.getInputStream());
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Object o = ois.readObject();
                    if(o instanceof String) {
                        String msg = (String) o;
                        System.out.println(msg);
                    }
                } catch (ClassNotFoundException | IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        Scanner s = new Scanner(System.in);
        while(true) {
            String msg = s.nextLine();
            oos.writeObject(msg);
        }
    }
}

这个 P2P 服务器/客户端应该有 1 个客户端向服务器发送消息,然后将该消息中继到另一个客户端。当从一个客户端发送消息时,服务器输出[Server] P2 sent 'hello',但是在将消息中继到另一个客户端后,另一个客户端得到了这个异常:

java.io.StreamCorruptedException: invalid type code: AC
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)
    at me.aj4real.tutorial.p2pChatServer.Client$1.run(Client.java:25)
    at java.lang.Thread.run(Unknown Source)

第 25 行是Object o = ois.readObject();

对象在从服务器中继后如何损坏? 我可以做些什么来防止对象被破坏?

【问题讨论】:

    标签: java sockets p2p objectinputstream objectoutputstream


    【解决方案1】:

    基本上问题是,您不应该使用相同的底层OutputStream 创建两个 ObjectOutputStream-s。您应该只为每个套接字创建一个对象输出流,然后重复使用它。

    所以错误是由行ObjectOutputStream p1out = ..ObjectOutputStream p2out = ..引起的。

    AC 代码来自“序列化标头”。如果我们看构造函数public ObjectOutputStream(OutputStream out)

    public ObjectOutputStream(OutputStream out) throws IOException {
        ...
        writeStreamHeader();
        ...
    }
    

    writeStreamHeader

    /**
     * Magic number that is written to the stream header.
     */
    final static short STREAM_MAGIC = (short)0xaced;
    ...
    protected void writeStreamHeader() throws IOException {
        bout.writeShort(STREAM_MAGIC);
        bout.writeShort(STREAM_VERSION);
    }
    

    所以如果创建了两个object-output-streams,头部会被写入两次,导致客户端反序列化错误。


    稍微修改过的服务器版本(为了说明目的,它以不同方式处理断开连接)。

    package clientserver;
    
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class Server {
      private static ServerSocket server;
      private static int port = 9876;
      private static Socket p1 = null;
      private static Socket p2 = null;
    
      static ObjectInputStream ois1, ois2;
      static ObjectOutputStream oos1, oos2;
    
      public static void main(String args[]) throws Exception {
        System.out.println("server listening on port=" + port);
        server = new ServerSocket(port);
    
        p1 = server.accept();
        System.out.println("[Server] P1 has connected");
        p2 = server.accept();
        System.out.println("[Server] P2 has connected");
    
        ois1 = new ObjectInputStream(p1.getInputStream());
        oos1 = new ObjectOutputStream(p1.getOutputStream());
        ois2 = new ObjectInputStream(p2.getInputStream());
        oos2 = new ObjectOutputStream(p2.getOutputStream());
    
        new Thread(new Runnable() {
          @Override
          public void run() {
            try {
              while (p1.isConnected()) {
                String message = (String) ois1.readObject();
                System.out.printf("[Server] P1 sent msg=[%s]%n", message);
                if (p2.isConnected()) {
                  ObjectOutputStream p2out = oos2;
                  p2out.writeObject("[P1] " + message);
                } else {
                  oos1.writeObject("[Server] P2 is not connected");
                }
              }
              System.out.println("[Server] P1 has disconnected");
            } catch (Exception e) {
              e.printStackTrace(System.out);
            }
          }
        }).start();
        new Thread(new Runnable() {
          @Override
          public void run() {
            try {
              while (p2.isConnected()) {
                String message = (String) ois2.readObject();
                System.out.printf("[Server] P2 sent msg=[%s]%n", message);
                if (p1.isConnected()) {
                  ObjectOutputStream p1out = oos1;
                  p1out.writeObject("[P2] " + message);
                } else {
                  oos2.writeObject("[Server] P1 is not connected");
                }
              }
              System.out.println("[Server] P2 has disconnected");
            } catch (Exception e) {
              e.printStackTrace(System.out);
            }
          }
        }).start();
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-26
      • 1970-01-01
      • 2012-06-08
      相关资源
      最近更新 更多