I am creating a multiplayer game in Java with a server and multiple clients. Everything runs perfectly, until I press the Kick-button in the server to kick a client.
Error at receive thread of server, after kicking the first person who joined out of three:
java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
at java.util.ArrayList.rangeCheck(ArrayList.java:604)
at java.util.ArrayList.get(ArrayList.java:382)
> at networktest.Server$3.run(Server.java:186)
at java.lang.Thread.run(Thread.java:722)
The pointed line is the ois = new ObjectInputStream where I receive datatype in the server receive thread. The server kicks the first person perfectly, but removes the second one in the list too, with an error of java.lang.ClassCastException.
server receive:
private static Thread receive = new Thread()
{
@Override
public void run()
{
ObjectInputStream ois;
while (true)
{
for (int i = 0; i < list_sockets.size(); i++)
{
try
{
ois = new ObjectInputStream(list_sockets.get(i).getInputStream());
int receive_state = (Integer) ois.readObject(); // receive state
ois = new ObjectInputStream(list_sockets.get(i).getInputStream());
byte datatype = (byte) ois.readObject(); // receive datatype
if(datatype == 2){
ois = new ObjectInputStream(list_sockets.get(i).getInputStream());
ChatLine chatLine = (ChatLine) ois.readObject(); // receive ChatLine
} else if (datatype == 0){
ois = new ObjectInputStream(list_sockets.get(i).getInputStream());
DataPackage dp = (DataPackage) ois.readObject(); // receive dp
list_data.set(i, dp);
}
if (receive_state == 1) // Client Disconnected by User
{
disconnectClient(i);
i--;
}
}
catch (Exception ex) // Client Disconnected (Client Didn't Notify Server About Disconnecting)
{
System.err.println("Error @ receive:");
ex.printStackTrace();
disconnectClient(i);
i--;
}
}
try {
this.sleep(3);
} catch (InterruptedException ex) {
Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
user send:
Thread send = new Thread()
{
public void run()
{
ObjectOutputStream oos;
byte datatype = 0;
while (connected){
if (socket != null){
try {
DataPackage dp = new DataPackage();
dp.x = Client.player.x;
dp.y = Client.player.y;
dp.username = username;
dp.charType = charType;
dp.walking = (byte)Client.player.walking;
if (Client.outputChatLine.line != null)
datatype = 2;
else {
datatype = 0;
}
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(Integer.valueOf(Client.this.state)); // send state
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(Byte.valueOf(datatype)); // send datatype
if (datatype == 2)
{
oos.reset();
oos.writeObject(Client.outputChatLine);
Client.outputChatLine = new ChatLine();
} else {
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(dp);
}
if (Client.this.state == 1) {
connected = false;
socket = null;
JOptionPane.showMessageDialog(null, "Client Disconnected", "Info", 1);
System.exit(0);
}
}
catch (Exception ex){}
}
try {
this.sleep(2);
} catch (InterruptedException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
disconnect client method:
public static void disconnectClient(int index)
{
try
{
list_clients_model.removeElementAt(index);
list_client_states.remove(index);
list_data.remove(index);
list_sockets.remove(index);
}
catch (Exception ex) {}
}
Does anyone know how to solve this?
It looks like you’re expecting some other thread to fill some data into
list_socketswhile you’resleep(3)ing. But you have no synchronization to ensure that this happens only while you’re sleeping.It could equally well happen that the other thread is updating
list_socketssimultaneously with your own thread callinglist_sockets.get(i). And the ArrayList implementation it is almost certainly not written to have two different of its methods executing simultaneously in two different threads. For example, the other thread could be in the middle of resizing the backing array when you’re trying to read an element, and then any crazy thing can go wrong, including the error you’re seeing.You need to learn about inter-thread synchronization. At the very least you need
synchronizedblocks to protect access to shared data structures. And while you’re at it; look atwait/notifyor some higher-level concurrency tools to get rid of that horrible 3-millisecond polling loop — instead have the thread that drops work into the list explicitly wake up the worker thread.