Reading from ObjectInputStream returns object only when connected
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 ObjectOutputSt开发者_如何学编程ream 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();
}
}
}
}
}
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.
精彩评论