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

时间:2011-05-26 16:41:16

标签: java multithreading sockets

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

  • Board - 是客户端之间共享的对象,序列化,Plain Old 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();
                    }
                }
            }

    }
}

1 个答案:

答案 0 :(得分:4)

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