Страницы

Поиск по вопросам

суббота, 11 апреля 2020 г.

Проблема с ObjectInputStream. (StreamCorruptedException: invalid type code: AC)

#сокеты #java

                    
Вообще изначальная задача - написать игру с двумя игроками, что-то типа точек.
т.е. один игрок (клиент) делает ход, отправляет данные (координаты x и y) на сервер.
Сервер обрабатывает эту информацию и отправляет сообщение с какими-то данными всем
подключенным клиентам. Все это надо реализовать на сокетах.
За основу взяла реализацию чата, но мне удобнее передавать объекты, поэтому использую
ObjectInputStream и ObjectOutputStream.
Написала пример: клиент вводит координаты x y, отправляет на сервер. На сервере хранится
матрица А. Получаем от клиента x,y, присваиваем A[x][y]=1, отправляем всем клиентам
объект класса ServerAnswer (матрица, x,y). Клиент получает и выводит матрицу. 
Для начала запускаю только один клиент. Первый раз все работает, но когда я ввожу
новые координаты на клиенте, они отправляются на сервер, он посылает ответ и на клиенте
при попытке выполнения - 
sa = (ServerAnswer)ois.readObject();

вылетает ошибка 
апр 17, 2014 12:06:45 PM client2.SocketInputThread run
SEVERE: null
java.io.StreamCorruptedException: invalid type code: AC
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1377)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at client2.SocketInputThread.run(SocketInputThread.java:37)
at java.lang.Thread.run(Thread.java:744)

Подскажите. пожалуйста, что не так в коде.
Код Сервера:
public class Server2 {

public static void main(String[] args) {
   System.out.println("Program starting...");
    try {
        ServerSocket ss = new ServerSocket(3129,0,
                InetAddress.getByName("localhost"));
        System.out.println("Server starting...");
        while(true){
            Socket s = ss.accept(); // ожидание новых клиентов
            SocketThread socketThread = new SocketThread(s);
            Thread t = new Thread(socketThread);
            t.start(); // запуск нового потока для каждого нового клиента
        }
    } catch (IOException ex) {
        Logger.getLogger(Server2.class.getName()).log(Level.SEVERE, null, ex);
    }

   }
 }

Класс SocketThread:
public class SocketThread implements Runnable {

private Socket s = null;

private boolean exit = true;
private int x = -1;
private int y = -1;
private int p = 0;
private int [][]A;
private ArrayList listSocket = null;
private ObjectInputStream ois = null; 
private ObjectOutputStream oos = null;

public SocketThread(Socket s) {
    this.s = s;
}

@Override
public void run() { 
    try {
        System.out.println("User connect...");
        ListSocket.addSocketToList(s); //  добавление текущого сокета с глобальной
список сокетов

        InputStream in = s.getInputStream();
        ois = new ObjectInputStream(in);//получаем от игрока новое ребро

         A = new int [5][5]; 
    for (int i = 0; i<5; i++)
        for (int j = 0; j < 5; j++)
    {
        A[i][j] = 0;
    }

    while (s.isConnected()) {

            Para new_p = (Para)ois.readObject();

             x = new_p.X();
             y = new_p.Y();                 
             p = new_p.P();

             A[x][y] = p;
             System.out.println(x + ";" + y);
             ServerAnswer sa = new ServerAnswer(5, 5);
             sa.SetAns(new_p, A);

            listSocket = ListSocket.getListSocket();
            for (Socket socket : listSocket) { // отсылка сообщения всем сокетам

              oos = new ObjectOutputStream(socket.getOutputStream());
                oos.writeObject(sa);
                oos.flush(); 
            }

        }
        ListSocket.removeSocketWithList(s); // если поток завершается то сокет
клиента удаляется из списка сокетов 
        System.out.println("User disconnect...");
    } catch (IOException ex) {
        try {
            s.close();
        } catch (IOException ex1) {
            Logger.getLogger(SocketThread.class.getName()).log(Level.SEVERE, null, ex1);
        }
        Logger.getLogger(SocketThread.class.getName()).log(Level.SEVERE, null, ex);
    } catch (ClassNotFoundException ex) {
        Logger.getLogger(SocketThread.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
}

Клиент:
public class Client2 {

public static void main(String[] args) {
    try {
        System.out.println("Client starting...");
         Socket s = new Socket("localhost",3129);
        System.out.println("Connect to server...");
        Thread threadIn = new Thread(new SocketInputThread(s));// создание отдельного
потока на считывание даных от сервера
        Thread threadOut = new Thread(new SocketOutputThread(s));// создание 
отдельного потока на ввод даных с клавиатуры
        threadIn.start();
        threadOut.start();
    } catch (UnknownHostException ex) {
        Logger.getLogger(Client2.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
        Logger.getLogger(Client2.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
}

SocketInputThread:
public class SocketInputThread implements Runnable {

private Socket s = null;
private ObjectInputStream ois = null;

public SocketInputThread(Socket s) {
    this.s = s;
}

@Override
public void run() {
    try {
        InputStream in = s.getInputStream();
        ois = new ObjectInputStream(in);

        while(true){
             ServerAnswer sa;

             sa = (ServerAnswer)ois.readObject();
             String str = "";

            for (int i=0; i


Ответы

Ответ 1



На один ObjectOutputStream должен приходиться ровно один ObjectInputStream Поясню: Корректный object stream выглядит так: [stream header], [object], [object], [object],... У вас object stream'ы выглядят так: [stream header], [object], [object], [stream header], [object], ... Stream header записывается каждый раз при создании нового ObjectOutputStream. Ваш invalid type code: AC означает, что ObjectInputStream ожидал прочитать объект, а прочитал хидер начала потока. То есть ошибка тут: for (Socket socket : listSocket) { // отсылка сообщения всем сокетам oos = new ObjectOutputStream(socket.getOutputStream()); Нужно хранить не список сокетов, чтобы каждый раз, проходясь по ним, создавать новые ObjectOutputStream'ы, а хранить список ObjectOutputStream'ов и переиспользовать их.

Комментариев нет:

Отправить комментарий