仅在连接时从 ObjectInputStream 读取才返回对象

发布于 2024-11-10 02:13:09 字数 4794 浏览 0 评论 0原文

我有一个简单的基于套接字的客户端-服务器应用程序,每个连接都有自己的线程。 目前的方案是这样的:

  • Board - 是在客户端之间共享的对象,序列化的普通旧 Java 对象
  • ActiveSessions - 所有连接都添加到列表中
  • BroadCaster - 当板发生更改时,将板发送到其他客户端

问题是每个线程连接并接收棋盘对象,但当再次发送时,它会再次发送相同的对象,但在服务器端该对象行为正确。

public static void main(String[] args) {
    Board gameBoard = new Board();
    ActiveSessions sessions = new ActiveSessions();
    Broadcaster broadcaster = new Broadcaster(sessions, gameBoard);

    try {
        ServerSocket socket = new ServerSocket(1234);
        // Timeout after what no more new connections are not accepted.
        socket.setSoTimeout(30 * 1000); 
        logger.info("Server started on port " + socket.getLocalPort());

        while (true) {
            SessionHandler session = new SessionHandler(socket.accept(), gameBoard, broadcaster);
            sessions.addSession(session);
            session.start();
        }

    } catch (SocketTimeoutException e1) {
        logger.info("No more new connecions are accpeted, start game or end");
        gameBoard.setGameState(GameState.PLAYING);
        logger.info("Set the gamestate to " + gameBoard.getGameState());
    } catch (IOException e) {
        logger.info("I/O error " + e.getMessage());
    }

SessionHandler,每个连接都有自己的线程 包服务器;

    import game.Board;
    import game.Turn;

    import java.io.EOFException;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.Socket;
    import java.net.SocketException;
    import java.util.logging.Logger;

    public class SessionHandler extends Thread {

        private Board gameBoard;
        private Socket socket;
        private Broadcaster broadcaster;
        private boolean firstConnect = true;

        private ObjectOutputStream out;
        private ObjectInputStream in;
        private static final Logger logger = Logger.getLogger(SocketServer.class.getName());

        public SessionHandler(Socket socket) {
            this.socket = socket; 
        }

        public SessionHandler(Socket accept, Board gameBoard, Broadcaster broadcaster) {
            this(accept);
            this.gameBoard = gameBoard;
            this.broadcaster = broadcaster;
        }

        @Override
        public void run() {
            try {
                out = new ObjectOutputStream(socket.getOutputStream());
                in = new ObjectInputStream(socket.getInputStream());

                while (true) {
                    Turn turn = (Turn) in.readObject();
                    if (turn != null) {
                        if (firstConnect) {
                            gameBoard.addPlayer(turn.getWhoseTurn());
                            firstConnect = false;
                        }

                        // Add the turn to game board and make validation
                        gameBoard.increaseTurns();
                        broadcaster.send();
                    }
                    System.out.println("Turns made " + gameBoard.getTurns() + " players " + gameBoard.getPlayers() + " dice score " + turn.getDiceScore());
                }
            } catch (EOFException e1) {
                logger.warning("Problem reading the object output");
            } catch (SocketException e) {
                if ("Connection reset".equals(e.getMessage())) {
                    System.out.println("Client disconnected, performing cleanup");
                } else {
                    logger.warning("Connection between client lost " + Thread.currentThread());
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(-1);
            }
        }

        public void sendTheGameBoard() {
            try {
                out.writeObject(this.gameBoard);
                out.flush();
            } catch (IOException e) {
                logger.warning("Problem with sending game board object " + e.getMessage());
            }
        }
    }
    class Broadcaster {

    private ActiveSessions activeSessions;

    public Broadcaster(ActiveSessions aa, Board board) {
        this.activeSessions = aa;
    }

    public void send() {
        // Broadcast board forever
            synchronized (activeSessions) {
                Iterator<SessionHandler> active = activeSessions.iterator();

                while (active.hasNext()) {
                    SessionHandler session = active.next();

                    if (!session.isAlive()) {
                        active.remove();
                        session.interrupt();
                    } else { 
                        session.sendTheGameBoard();
                    }
                }
            }

    }
}

I got simple socket based client - server application, each connection gets own thread.
Currently scheme is something like this:

  • Board - is the object to share between the clients, serialized, Plain Old Java object
  • ActiveSessions - all the connections are added into list
  • BroadCaster - when the board has changed, send the board to other clients

Problem is that each thread connects and recevies the board object but when it's sent again it sends again the same object, but on the serverside the object behaves correctly.

public static void main(String[] args) {
    Board gameBoard = new Board();
    ActiveSessions sessions = new ActiveSessions();
    Broadcaster broadcaster = new Broadcaster(sessions, gameBoard);

    try {
        ServerSocket socket = new ServerSocket(1234);
        // Timeout after what no more new connections are not accepted.
        socket.setSoTimeout(30 * 1000); 
        logger.info("Server started on port " + socket.getLocalPort());

        while (true) {
            SessionHandler session = new SessionHandler(socket.accept(), gameBoard, broadcaster);
            sessions.addSession(session);
            session.start();
        }

    } catch (SocketTimeoutException e1) {
        logger.info("No more new connecions are accpeted, start game or end");
        gameBoard.setGameState(GameState.PLAYING);
        logger.info("Set the gamestate to " + gameBoard.getGameState());
    } catch (IOException e) {
        logger.info("I/O error " + e.getMessage());
    }

SessionHandler, each connection has own thread
package server;

    import game.Board;
    import game.Turn;

    import java.io.EOFException;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.net.Socket;
    import java.net.SocketException;
    import java.util.logging.Logger;

    public class SessionHandler extends Thread {

        private Board gameBoard;
        private Socket socket;
        private Broadcaster broadcaster;
        private boolean firstConnect = true;

        private ObjectOutputStream out;
        private ObjectInputStream in;
        private static final Logger logger = Logger.getLogger(SocketServer.class.getName());

        public SessionHandler(Socket socket) {
            this.socket = socket; 
        }

        public SessionHandler(Socket accept, Board gameBoard, Broadcaster broadcaster) {
            this(accept);
            this.gameBoard = gameBoard;
            this.broadcaster = broadcaster;
        }

        @Override
        public void run() {
            try {
                out = new ObjectOutputStream(socket.getOutputStream());
                in = new ObjectInputStream(socket.getInputStream());

                while (true) {
                    Turn turn = (Turn) in.readObject();
                    if (turn != null) {
                        if (firstConnect) {
                            gameBoard.addPlayer(turn.getWhoseTurn());
                            firstConnect = false;
                        }

                        // Add the turn to game board and make validation
                        gameBoard.increaseTurns();
                        broadcaster.send();
                    }
                    System.out.println("Turns made " + gameBoard.getTurns() + " players " + gameBoard.getPlayers() + " dice score " + turn.getDiceScore());
                }
            } catch (EOFException e1) {
                logger.warning("Problem reading the object output");
            } catch (SocketException e) {
                if ("Connection reset".equals(e.getMessage())) {
                    System.out.println("Client disconnected, performing cleanup");
                } else {
                    logger.warning("Connection between client lost " + Thread.currentThread());
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(-1);
            }
        }

        public void sendTheGameBoard() {
            try {
                out.writeObject(this.gameBoard);
                out.flush();
            } catch (IOException e) {
                logger.warning("Problem with sending game board object " + e.getMessage());
            }
        }
    }
    class Broadcaster {

    private ActiveSessions activeSessions;

    public Broadcaster(ActiveSessions aa, Board board) {
        this.activeSessions = aa;
    }

    public void send() {
        // Broadcast board forever
            synchronized (activeSessions) {
                Iterator<SessionHandler> active = activeSessions.iterator();

                while (active.hasNext()) {
                    SessionHandler session = active.next();

                    if (!session.isAlive()) {
                        active.remove();
                        session.interrupt();
                    } else { 
                        session.sendTheGameBoard();
                    }
                }
            }

    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

负佳期 2024-11-17 02:13:09

阅读 http://java.sun.com/javase/technologies/ core/basic/serializationFAQ.jsp#handle。 ObjectOutputStream 有一个缓存,以避免多次发送同一个对象。您必须重置流才能再次发送副本。

Read http://java.sun.com/javase/technologies/core/basic/serializationFAQ.jsp#handle. The ObjectOutputStream has a cache in order to avoid sending the same object multiple times. You must reset the stream to send a copy again.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文