问题描述
|
我有一个基于套接字的简单客户端-服务器应用程序,每个连接都有自己的线程。
当前方案是这样的:
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();
}
}
}
}
}
解决方法
阅读http://java.sun.com/javase/technologies/core/basic/serializationFAQ.jsp#handle。 ObjectOutputStream具有一个缓存,以避免多次发送同一对象。您必须重置流以再次发送副本。