1
我得到了一個簡單的基於套接字的客戶端 - 服務器應用程序,每個連接都獲得自己的線程。 目前的方案是這樣的:從ObjectInputStream中讀取僅在連接時返回對象
- 板 - 是客戶,系列化,普通Java對象
- ActiveSessions之間共享的對象 - 所有的連接被添加到列表
- 廣播公司 - 當董事會已改變,董事會發送給其他客戶
問題是,每個線程連接和recevies董事會對象,但是當它再次發送再次發送相同的對象,但在服務器端對象行爲正確。
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();
}
}
}
}
}
謝謝你,我尋找修復很多小時,並沒有找到這個。我通過添加reset()更正了發送代碼。 – 2011-05-26 17:03:49
你也可以使用'writeUnshared()'每次發送對象的新副本。但是'reset()'對於避免內存泄漏很有用。如果你不叫它,它會記住你發送的每一個對象。 ;) – 2011-05-26 17:13:54
@Peter Lawrey @jurka澄清:寫僅共享'unshares'提供給writeObject()的實際對象。它引用的任何對象都保持共享。重置()'取消'所有寫入到目前爲止。 – EJP 2011-05-27 00:59:50