Неверная передача объекта серверу java

Я пишу онлайн игру и возникла проблема: пересылка объекта клавиатуры. Клиент отправляет экземпляр, у которого в свойствах указано, что клавиша нажата, а сервер получает объект, у которого указано в свойствах, что клавиша отпущена.

Написал небольшой пример, иллюстрирующий это. Кто сможет помочь, буду благодарен.

Код:

тестовый класс:


import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;

public class TCPPhoneSerialization {
    private static final int PORT = 26781;
    private static final String ADDRESS = "127.0.0.1";

    public static void main(String[] args) {
        new Thread(() -> {
            try (ServerSocket server = new ServerSocket(PORT)) {
                System.out.println("Server started on port: " + PORT);
                TCPSerPhone1 client = new TCPSerPhone1(server);
                System.out.println("Server: Client connected with ip address: " + client.getIp());
                KeysListener keysboard;
                while (true) {
                    Object res = client.readObject();
                    //System.out.println(res.getClass());
                    keysboard = (KeysListener) res;
                    System.out.println("Server: " + Arrays.toString(keysboard.keys));
                    Thread.sleep(200);
                }

            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            KeysListener keys = new KeysListener();
            JFrame keyReader = new JFrame();
            keyReader.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            keyReader.setBounds(new Rectangle(200, 200, 400, 400));
            keyReader.setVisible(true);
            keyReader.addKeyListener(keys);

            try (TCPSerPhone1 client = new TCPSerPhone1(ADDRESS, PORT)) {
                System.out.println("Client: Player connected to server with ip: " + ADDRESS + " on port " + PORT);
                while (true) {
                    client.writeObject(keys);
                    System.out.println("Client: " + Arrays.toString(keys.keys));
                    Thread.sleep(200);
                }

            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

class KeysListener implements KeyListener, Serializable {
    //все клавиши, которыек нам нужны
    public final boolean[] keys = new boolean[4];

    public KeysListener() {
    }

    public void keyPressed(KeyEvent event) {
        if (event.getKeyChar() == 'a')
            keys[0] = true;
        if (event.getKeyChar() == 'd')
            keys[1] = true;
        if (event.getKeyChar() == 's')
            keys[2] = true;
        if (event.getKeyChar() == 'w')
            keys[3] = true;
    }

    public void keyReleased(KeyEvent event) {
        if (event.getKeyChar() == 'a')
            keys[0] = false;
        if (event.getKeyChar() == 'd')
            keys[1] = false;
        if (event.getKeyChar() == 's')
            keys[2] = false;
        if (event.getKeyChar() == 'w')
            keys[3] = false;
    }

    public void keyTyped(KeyEvent event) {
    }
}

class TCPSerPhone1 implements Closeable {
    private final Socket socket; //сам сокет
    //потоки для чтения / записи
    private final ObjectInputStream objectReader;
    private final ObjectOutputStream objectWriter;
    //закрыт ли сокет (для сервера)
    public boolean closed = false;

    //конструктор для клиента
    public TCPSerPhone1(String ip, int port) {
        try {
            this.socket = new Socket(ip, port);
            this.objectWriter = createObjectWriter();
            this.objectReader = createObjectReader();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //конструктор для сервера
    public TCPSerPhone1(ServerSocket server) {
        try {
            this.socket = server.accept();//ожидание клиентов
            this.objectWriter = new ObjectOutputStream(socket.getOutputStream());
            this.objectReader = new ObjectInputStream(socket.getInputStream());
            objectWriter.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //получение ip адреса в виде строки через сокет
    public String getIp() {
        return socket.getInetAddress().getHostAddress();
    }

    //отправка сообщения
    public int writeObject(Serializable obj) {
        if (!closed) {
            try {
                objectWriter.writeObject(obj);
                objectWriter.flush();
                return 0;
            } catch (IOException e) {
                e.printStackTrace();
                return -1; //попытка отправки оффлайн киенту
            }
        }
        return -2; //сокет сервера закрыт
    }

    public Object readObject() {
        if (!closed) {
            try {
                return objectReader.readObject();
            } catch (IOException | ClassNotFoundException e) {
                //e.printStackTrace();
                return "-1"; //попытка отправки оффлайн киенту
            }
        }
        return "-2"; //сокет сервера закрыт
    }

    //создание потока ввода
    private ObjectInputStream createObjectReader() throws IOException {
        return new ObjectInputStream(socket.getInputStream());
    }

    //создание потока вывода
    private ObjectOutputStream createObjectWriter() throws IOException {
        return new ObjectOutputStream(socket.getOutputStream());
    }

    //чтобы можно было использовать try-catch with resources
    @Override
    public void close() throws IOException {
        closed = true;
        objectReader.close();
        objectWriter.close();
        socket.close();
    }
}

Ответы (0 шт):