mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Fixed disconnection issues. Fix is only temporary until a consistent interface for disconnections exists.
#bug #implement
This commit is contained in:
@@ -93,6 +93,9 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
|
|
||||||
// TODO: 14/07/17 wmu16 - Send out disconnect packet to clients
|
// TODO: 14/07/17 wmu16 - Send out disconnect packet to clients
|
||||||
try {
|
try {
|
||||||
|
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
||||||
|
serverToClientThread.terminate();
|
||||||
|
}
|
||||||
serverSocket.close();
|
serverSocket.close();
|
||||||
return;
|
return;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -173,6 +176,7 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
thread.sendSetupMessages();
|
thread.sendSetupMessages();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
serverToClientThread.addDisconnectListener(this::clientDisconnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -182,11 +186,11 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void clientDisconnected(Player player) {
|
public void clientDisconnected(Player player) {
|
||||||
try {
|
// try {
|
||||||
player.getSocket().close();
|
// player.getSocket().close();
|
||||||
} catch (Exception e) {
|
// } catch (Exception e) {
|
||||||
serverLog("Cannot disconnect the socket for the disconnected player.", 0);
|
// serverLog("Cannot disconnect the socket for the disconnected player.", 0);
|
||||||
}
|
// }
|
||||||
serverLog("Player " + player.getYacht().getSourceId() + "'s socket disconnected", 0);
|
serverLog("Player " + player.getYacht().getSourceId() + "'s socket disconnected", 0);
|
||||||
GameState.removeYacht(player.getYacht().getSourceId());
|
GameState.removeYacht(player.getYacht().getSourceId());
|
||||||
GameState.removePlayer(player);
|
GameState.removePlayer(player);
|
||||||
@@ -194,11 +198,12 @@ public class MainServerThread implements Runnable, ClientConnectionDelegate {
|
|||||||
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
for (ServerToClientThread serverToClientThread : serverToClientThreads) {
|
||||||
if (serverToClientThread.getSocket() == player.getSocket()) {
|
if (serverToClientThread.getSocket() == player.getSocket()) {
|
||||||
closedConnection = serverToClientThread;
|
closedConnection = serverToClientThread;
|
||||||
} else {
|
} else if (GameState.getCurrentStage() != GameStages.RACING){
|
||||||
serverToClientThread.sendSetupMessages();
|
serverToClientThread.sendSetupMessages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serverToClientThreads.remove(closedConnection);
|
serverToClientThreads.remove(closedConnection);
|
||||||
|
closedConnection.terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startGame() {
|
public void startGame() {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class ServerListenThread implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void run(){
|
public void run(){
|
||||||
while (true){
|
while (serverSocket != null && !serverSocket.isClosed()){
|
||||||
acceptConnection();
|
acceptConnection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,26 +19,22 @@ import java.util.zip.CRC32;
|
|||||||
import java.util.zip.Checksum;
|
import java.util.zip.Checksum;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import seng302.gameServer.messages.BoatAction;
|
||||||
|
import seng302.gameServer.messages.BoatLocationMessage;
|
||||||
|
import seng302.gameServer.messages.ClientType;
|
||||||
|
import seng302.gameServer.messages.Message;
|
||||||
|
import seng302.gameServer.messages.RegistrationResponseMessage;
|
||||||
|
import seng302.gameServer.messages.RegistrationResponseStatus;
|
||||||
|
import seng302.gameServer.messages.XMLMessage;
|
||||||
|
import seng302.gameServer.messages.XMLMessageSubType;
|
||||||
import seng302.gameServer.messages.YachtEventCodeMessage;
|
import seng302.gameServer.messages.YachtEventCodeMessage;
|
||||||
import seng302.model.Player;
|
import seng302.model.Player;
|
||||||
|
import seng302.model.ServerYacht;
|
||||||
import seng302.model.stream.packets.PacketType;
|
import seng302.model.stream.packets.PacketType;
|
||||||
import seng302.model.stream.packets.StreamPacket;
|
import seng302.model.stream.packets.StreamPacket;
|
||||||
import seng302.model.stream.xml.generator.Race;
|
import seng302.model.stream.xml.generator.Race;
|
||||||
import seng302.model.stream.xml.generator.Regatta;
|
import seng302.model.stream.xml.generator.Regatta;
|
||||||
import seng302.utilities.XMLGenerator;
|
import seng302.utilities.XMLGenerator;
|
||||||
import seng302.gameServer.messages.BoatAction;
|
|
||||||
import seng302.gameServer.messages.BoatLocationMessage;
|
|
||||||
import seng302.gameServer.messages.BoatSubMessage;
|
|
||||||
import seng302.gameServer.messages.ClientType;
|
|
||||||
import seng302.gameServer.messages.Message;
|
|
||||||
import seng302.gameServer.messages.RaceStatus;
|
|
||||||
import seng302.gameServer.messages.RaceStatusMessage;
|
|
||||||
import seng302.gameServer.messages.RaceType;
|
|
||||||
import seng302.gameServer.messages.RegistrationResponseMessage;
|
|
||||||
import seng302.gameServer.messages.RegistrationResponseStatus;
|
|
||||||
import seng302.gameServer.messages.XMLMessage;
|
|
||||||
import seng302.gameServer.messages.XMLMessageSubType;
|
|
||||||
import seng302.model.ServerYacht;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class describing a single connection to a Client for the purposes of sending and receiving on
|
* A class describing a single connection to a Client for the purposes of sending and receiving on
|
||||||
@@ -55,6 +51,12 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
void notifyConnection ();
|
void notifyConnection ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: 17/08/17 this is only temporary disconnects should be handled consistently
|
||||||
|
@FunctionalInterface
|
||||||
|
interface DisconnectListener {
|
||||||
|
void notifyDisconnect (Player player);
|
||||||
|
}
|
||||||
|
|
||||||
private Logger logger = LoggerFactory.getLogger(ServerToClientThread.class);
|
private Logger logger = LoggerFactory.getLogger(ServerToClientThread.class);
|
||||||
|
|
||||||
private Thread thread;
|
private Thread thread;
|
||||||
@@ -74,8 +76,10 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
private XMLGenerator xml;
|
private XMLGenerator xml;
|
||||||
|
|
||||||
private List<ConnectionListener> connectionListeners = new ArrayList<>();
|
private List<ConnectionListener> connectionListeners = new ArrayList<>();
|
||||||
|
private DisconnectListener disconnectListener;
|
||||||
|
|
||||||
private ServerYacht yacht;
|
private ServerYacht yacht;
|
||||||
|
private Player player;
|
||||||
|
|
||||||
public ServerToClientThread(Socket socket) {
|
public ServerToClientThread(Socket socket) {
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
@@ -122,8 +126,9 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
);
|
);
|
||||||
|
|
||||||
yacht.addObserver(this); // TODO: yacht can notify mark rounding message hyi25 13/8/17
|
yacht.addObserver(this); // TODO: yacht can notify mark rounding message hyi25 13/8/17
|
||||||
|
player = new Player(socket, yacht);
|
||||||
GameState.addYacht(sourceId, yacht);
|
GameState.addYacht(sourceId, yacht);
|
||||||
GameState.addPlayer(new Player(socket, yacht));
|
GameState.addPlayer(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -169,8 +174,7 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
int sync2;
|
int sync2;
|
||||||
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
|
// TODO: 14/07/17 wmu16 - Work out how to fix this while loop
|
||||||
|
|
||||||
while (socket.isConnected()) {
|
while (socket.isConnected() && !socket.isClosed()) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
crcBuffer = new ByteArrayOutputStream();
|
crcBuffer = new ByteArrayOutputStream();
|
||||||
sync1 = readByte();
|
sync1 = readByte();
|
||||||
@@ -213,6 +217,7 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
logger.warn("Closed serverToClientThread" + thread, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendSetupMessages() {
|
public void sendSetupMessages() {
|
||||||
@@ -252,11 +257,12 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
private int readByte() throws Exception {
|
private int readByte() throws Exception {
|
||||||
int currentByte = -1;
|
int currentByte = -1;
|
||||||
try {
|
try {
|
||||||
// @TODO @FIX ConnectionReset Exception when a client disconnects before it is garbage collected
|
|
||||||
currentByte = is.read();
|
currentByte = is.read();
|
||||||
crcBuffer.write(currentByte);
|
crcBuffer.write(currentByte);
|
||||||
|
} catch (SocketException se) {
|
||||||
|
disconnectListener.notifyDisconnect(this.player);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
disconnectListener.notifyDisconnect(this.player);
|
||||||
logger.warn("Socket read failed", 1);
|
logger.warn("Socket read failed", 1);
|
||||||
}
|
}
|
||||||
if (currentByte == -1) {
|
if (currentByte == -1) {
|
||||||
@@ -335,4 +341,16 @@ public class ServerToClientThread implements Runnable, Observer {
|
|||||||
public void removeConnectionListener(ConnectionListener listener) {
|
public void removeConnectionListener(ConnectionListener listener) {
|
||||||
connectionListeners.remove(listener);
|
connectionListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void terminate () {
|
||||||
|
try {
|
||||||
|
socket.close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
logger.warn("IOException attempting to terminate serverToClientThread " + this.thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDisconnectListener(DisconnectListener disconnectListener) {
|
||||||
|
this.disconnectListener = disconnectListener;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,18 +142,20 @@ public class ClientToServerThread implements Runnable {
|
|||||||
}
|
}
|
||||||
} catch (ByteReadException e) {
|
} catch (ByteReadException e) {
|
||||||
logger.warn("Byte read exception on ClientToServerThread", 1);
|
logger.warn("Byte read exception on ClientToServerThread", 1);
|
||||||
closeSocket();
|
|
||||||
notifyDisconnectListeners("Connection to server was interrupted");
|
notifyDisconnectListeners("Connection to server was interrupted");
|
||||||
|
closeSocket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.warn("Closed connection to server", 1);
|
logger.warn("Closed connection to server", 1);
|
||||||
closeSocket();
|
|
||||||
notifyDisconnectListeners("Connection to server was terminated");
|
notifyDisconnectListeners("Connection to server was terminated");
|
||||||
|
closeSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyDisconnectListeners (String message) {
|
private void notifyDisconnectListeners (String message) {
|
||||||
for (DisconnectedFromHostListener listener : disconnectionListeners) {
|
if (socketOpen) {
|
||||||
listener.notifYDisconnection(message);
|
for (DisconnectedFromHostListener listener : disconnectionListeners) {
|
||||||
|
listener.notifYDisconnection(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,8 +169,8 @@ public class ClientToServerThread implements Runnable {
|
|||||||
os.write(requestMessage.getBuffer());
|
os.write(requestMessage.getBuffer());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.error("Could not send registration request. Exiting");
|
logger.error("Could not send registration request. Exiting");
|
||||||
closeSocket();
|
|
||||||
notifyDisconnectListeners("Failed to register with server");
|
notifyDisconnectListeners("Failed to register with server");
|
||||||
|
closeSocket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,8 +199,8 @@ public class ClientToServerThread implements Runnable {
|
|||||||
else{
|
else{
|
||||||
alertErrorText = "Could not connect to server";
|
alertErrorText = "Could not connect to server";
|
||||||
}
|
}
|
||||||
closeSocket();
|
|
||||||
notifyDisconnectListeners(alertErrorText);
|
notifyDisconnectListeners(alertErrorText);
|
||||||
|
closeSocket();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,7 +210,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
* - MAINTAIN_HEADING = DOWNWIND and UPWIND packets stop being sent.
|
* - MAINTAIN_HEADING = DOWNWIND and UPWIND packets stop being sent.
|
||||||
* @param actionType The boat action that will dictate packets sent.
|
* @param actionType The boat action that will dictate packets sent.
|
||||||
*/
|
*/
|
||||||
public void sendBoatActionMessage(BoatAction actionType) {
|
public void sendBoatAction(BoatAction actionType) {
|
||||||
switch (actionType) {
|
switch (actionType) {
|
||||||
case MAINTAIN_HEADING:
|
case MAINTAIN_HEADING:
|
||||||
if (upwindTimerFlag) {
|
if (upwindTimerFlag) {
|
||||||
@@ -272,9 +274,9 @@ public class ClientToServerThread implements Runnable {
|
|||||||
try {
|
try {
|
||||||
os.write(message.getBuffer());
|
os.write(message.getBuffer());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("IOException on attempting to sendBoatActionMessage from Client");
|
logger.warn("IOException on attempting to sendBoatAction from Client");
|
||||||
closeSocket();
|
|
||||||
notifyDisconnectListeners("Cannot communicate with server");
|
notifyDisconnectListeners("Cannot communicate with server");
|
||||||
|
closeSocket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,6 +284,7 @@ public class ClientToServerThread implements Runnable {
|
|||||||
private void closeSocket() {
|
private void closeSocket() {
|
||||||
try {
|
try {
|
||||||
socket.close();
|
socket.close();
|
||||||
|
socketOpen = false;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("IOException on attempting to close ClientToServerSocket");
|
logger.warn("IOException on attempting to close ClientToServerSocket");
|
||||||
}
|
}
|
||||||
@@ -318,8 +321,8 @@ public class ClientToServerThread implements Runnable {
|
|||||||
crcBuffer.write(currentByte);
|
crcBuffer.write(currentByte);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("IOException on readByte Client side", 1);
|
logger.warn("IOException on readByte Client side", 1);
|
||||||
closeSocket();
|
|
||||||
notifyDisconnectListeners("Cannot read from server.");
|
notifyDisconnectListeners("Cannot read from server.");
|
||||||
|
closeSocket();
|
||||||
}
|
}
|
||||||
if (currentByte == -1) {
|
if (currentByte == -1) {
|
||||||
throw new ByteReadException("InputStream reach end of stream");
|
throw new ByteReadException("InputStream reach end of stream");
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ public class GameClient {
|
|||||||
* @param portNumber Port to connect to.
|
* @param portNumber Port to connect to.
|
||||||
*/
|
*/
|
||||||
public void runAsHost(String ipAddress, Integer portNumber) {
|
public void runAsHost(String ipAddress, Integer portNumber) {
|
||||||
|
server = new MainServerThread();
|
||||||
try {
|
try {
|
||||||
startClientToServerThread(ipAddress, portNumber);
|
startClientToServerThread(ipAddress, portNumber);
|
||||||
socketThread.addDisconnectionListener((cause) -> {
|
socketThread.addDisconnectionListener((cause) -> {
|
||||||
@@ -126,6 +127,8 @@ public class GameClient {
|
|||||||
lobbyController.disableReadyButton();
|
lobbyController.disableReadyButton();
|
||||||
server.startGame();
|
server.startGame();
|
||||||
} else if (exitCause == CloseStatus.LEAVE) {
|
} else if (exitCause == CloseStatus.LEAVE) {
|
||||||
|
server.terminate();
|
||||||
|
server = null;
|
||||||
loadStartScreen();
|
loadStartScreen();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -370,13 +373,13 @@ public class GameClient {
|
|||||||
private void keyPressed(KeyEvent e) {
|
private void keyPressed(KeyEvent e) {
|
||||||
switch (e.getCode()) {
|
switch (e.getCode()) {
|
||||||
case SPACE: // align with vmg
|
case SPACE: // align with vmg
|
||||||
socketThread.sendBoatActionMessage(BoatAction.VMG); break;
|
socketThread.sendBoatAction(BoatAction.VMG); break;
|
||||||
case PAGE_UP: // upwind
|
case PAGE_UP: // upwind
|
||||||
socketThread.sendBoatActionMessage(BoatAction.UPWIND); break;
|
socketThread.sendBoatAction(BoatAction.UPWIND); break;
|
||||||
case PAGE_DOWN: // downwind
|
case PAGE_DOWN: // downwind
|
||||||
socketThread.sendBoatActionMessage(BoatAction.DOWNWIND); break;
|
socketThread.sendBoatAction(BoatAction.DOWNWIND); break;
|
||||||
case ENTER: // tack/gybe
|
case ENTER: // tack/gybe
|
||||||
socketThread.sendBoatActionMessage(BoatAction.TACK_GYBE); break;
|
socketThread.sendBoatAction(BoatAction.TACK_GYBE); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,12 +388,12 @@ public class GameClient {
|
|||||||
switch (e.getCode()) {
|
switch (e.getCode()) {
|
||||||
//TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet)
|
//TODO 12/07/17 Determine the sail state and send the appropriate packet (eg. if sails are in, send a sail out packet)
|
||||||
case SHIFT: // sails in/sails out
|
case SHIFT: // sails in/sails out
|
||||||
socketThread.sendBoatActionMessage(BoatAction.SAILS_IN);
|
socketThread.sendBoatAction(BoatAction.SAILS_IN);
|
||||||
allBoatsMap.get(socketThread.getClientId()).toggleSail();
|
allBoatsMap.get(socketThread.getClientId()).toggleSail();
|
||||||
break;
|
break;
|
||||||
case PAGE_UP:
|
case PAGE_UP:
|
||||||
case PAGE_DOWN:
|
case PAGE_DOWN:
|
||||||
socketThread.sendBoatActionMessage(BoatAction.MAINTAIN_HEADING); break;
|
socketThread.sendBoatAction(BoatAction.MAINTAIN_HEADING); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package seng302.visualiser.ClientToServerTests;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import seng302.gameServer.MainServerThread;
|
||||||
|
import seng302.visualiser.ClientToServerThread;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by cir27 on 17/08/17.
|
||||||
|
*/
|
||||||
|
public class DisconnectionTest {
|
||||||
|
@Test
|
||||||
|
public void testServerDisconnection () throws Exception {
|
||||||
|
MainServerThread serverThread = new MainServerThread();
|
||||||
|
ClientToServerThread clientThread = new ClientToServerThread("localhost", 4942);
|
||||||
|
Thread.sleep(1000);
|
||||||
|
clientThread.addDisconnectionListener(message -> Assert.assertTrue(message != null));
|
||||||
|
serverThread.terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,7 +61,7 @@ public class RegularPacketsTest {
|
|||||||
// SleepThreadMaxDelay();
|
// SleepThreadMaxDelay();
|
||||||
// ServerYacht yacht = new ArrayList<>(GameState.getYachts().values()).get(0);
|
// ServerYacht yacht = new ArrayList<>(GameState.getYachts().values()).get(0);
|
||||||
// boolean startState = yacht.getSailIn();
|
// boolean startState = yacht.getSailIn();
|
||||||
// clientThread.sendBoatActionMessage(BoatAction.SAILS_IN);
|
// clientThread.sendBoatAction(BoatAction.SAILS_IN);
|
||||||
// SleepThreadMaxDelay();
|
// SleepThreadMaxDelay();
|
||||||
// Assert.assertEquals(startState, !yacht.getSailIn());
|
// Assert.assertEquals(startState, !yacht.getSailIn());
|
||||||
// }
|
// }
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class ToggleSailSteps {
|
|||||||
public void the_user_has_pressed(String arg1) throws Throwable {
|
public void the_user_has_pressed(String arg1) throws Throwable {
|
||||||
startTime = System.currentTimeMillis();
|
startTime = System.currentTimeMillis();
|
||||||
if (arg1 == "shift") {
|
if (arg1 == "shift") {
|
||||||
client.sendBoatActionMessage(BoatAction.SAILS_IN);
|
client.sendBoatAction(BoatAction.SAILS_IN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user