0

サーバーと複数のクライアントを使用して Java でマルチプレイヤー ゲームを作成しています。サーバーのキックボタンを押してクライアントをキックするまで、すべてが完全に実行されます。

3人のうち最初に参加した人をキックした後、サーバーの受信スレッドでエラーが発生しました:

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)

指摘された行は、サーバー受信スレッドでデータ型を受信するois = new ObjectInputStreamです。サーバーは最初の人を完全にキックしますが、リストの 2 番目の人も削除し、java.lang.ClassCastExceptionのエラーが発生します。

サーバー受信:

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);
                            }
        }
    }
};

ユーザー送信:

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);
            }
        }
    }
};

クライアントの切断方法:

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) {}
}

これを解決する方法を知っている人はいますか?

4

1 に答える 1

0

実行中に他のスレッドがデータを入力することを期待しているようlist_socketsですsleep(3)。ただし、これが睡眠中にのみ発生することを保証する同期はありません。

自分のスレッドlist_sockets list_sockets.get(i). また、ArrayList の実装では、2 つの異なるスレッドで同時に実行される 2 つの異なるメソッドを持つように記述されていないことはほぼ確実です。たとえば、要素を読み込もうとしているときに、他のスレッドがバッキング配列のサイズを変更している最中である可能性があり、表示されているエラーを含め、異常な事態が発生する可能性があります。

スレッド間同期について学ぶ必要があります。少なくともsynchronized、共有データ構造へのアクセスを保護するブロックが必要です。そして、あなたがそれをしている間。wait/notifyまたはその恐ろしい 3 ミリ秒のポーリング ループを取り除くために、いくつかの高レベルの同時実行ツールを調べてください。

于 2012-09-13T21:59:38.027 に答える