Вопрос по multithreading, objectoutputstream, sockets, java – java.io.StreamCorruptedException: неверный код типа: 00

8

В общем, я пишу многопользовательскую игру клиент-сервер. У меня есть SeverCommunicationThread, который создает gameThread, если он получает RequestForGame создает gameThread. При отправке исключения RequestForGame выбрасывается исключение java.io.StreamCorruptedException: недопустимый код типа: 00 Я предполагаю, что это потому, что оба потока пытаются прочитать один и тот же ObjectInputStream, у меня нет большого понимания того, как он работает, я просто знаю, как его использовать. Не могли бы вы помочь мне понять, в чем проблема и как ее исправить? Спасибо :)

public class ServerCommunicationThread extends Thread{
private Socket connectionSocket;
private ObjectInputStream inFromClient;
private ObjectOutputStream outToClient;
private String nickname;
private ServerModelManager model;


public ServerCommunicationThread(Socket connectionSocket,
        ServerModelManager model) throws IOException {
    this.connectionSocket = connectionSocket;
    inFromClient = new ObjectInputStream(connectionSocket.getInputStream());
    outToClient = new ObjectOutputStream(connectionSocket.getOutputStream());
    this.model = model;
    start();

}

public void run() {
    try {
        String nickname = (String) inFromClient.readObject();
        if (model.exists(nickname)){
            System.out.println(nickname + " already exists");
            outToClient.writeObject(new MessageForClient("Please choose another nickname"));
        }
        else
        {
            System.out.println(nickname + " connected, adding to list");
            model.addClient(nickname, connectionSocket,outToClient,inFromClient);
            this.nickname=nickname;
        }
        while(true){
            Object o= inFromClient.readObject();//StreamCorruptedexception
            if(o instanceof RequestForGame)
            {
                RequestForGame r=(RequestForGame)o;
                String userToPlayWith=r.getUserToPlayWith();
                if(userToPlayWith.equals(nickname))
                {
                    String message="Playing with yourself makes your palms hairy, choose another opponent";
                    outToClient.writeObject(message);
                }
                else
                {
                System.out.println("received request to play with "+userToPlayWith+". starting game");
                ClientRepresentative client1=model.getClient(nickname);
                ClientRepresentative client2=model.getClient(userToPlayWith);
                ServerGameThread s=new ServerGameThread(client2,client1,client2.getInStream(),client1.getInStream(),client1.getOutStream(),client2.getOutStream());
                }
            }
            else if(o instanceof String)
            {
                String s=(String) o;
                if(s.equals("i want to quit"))
                {
                    model.deleteClient(nickname);
                    inFromClient.close();
                    String q="quit";
                    outToClient.writeObject(q);
                    connectionSocket.close();
                    System.out.println(nickname+"has quit without exc");
                }
            }
        }
    } catch (EOFException e) {
        System.out.println(nickname+" has quit");
    }
    catch (SocketException e)
    {
        System.out.println(nickname+" has quit");
    }

    catch (Exception e) {

        e.printStackTrace();
    }
}

}
 public class ServerGameThread extends Thread {

private ClientRepresentative client1,client2;
private ObjectInputStream inFromClient1,inFromClient2;
private ObjectOutputStream outToClient1,outToClient2;
private Field gameField; 
public ServerGameThread(ClientRepresentative client1, ClientRepresentative client2,ObjectInputStream inFromClient1,ObjectInputStream inFromClient2,ObjectOutputStream outToClient1,ObjectOutputStream outToClient2)
{
    System.out.println("startin game thred");
    this.client1=client1;//client 1 goes first
    this.client2=client2;//client 2 started game


        this.inFromClient1=inFromClient1;
        this.inFromClient2=inFromClient2;
        this.outToClient1=outToClient1;
        this.outToClient2=outToClient2;


        gameField=new Field();
        System.out.println("check");
        start();
}
public void run()
{
    System.out.println("Starting game. players: "+client1.getNickname()+";"+client2.getNickname());
    try {
        outToClient1.writeObject(gameField);
        outToClient2.writeObject(gameField);
        while(true)
        {
            try {
                System.out.println("listening to "+client1.getNickname());
                Object o1=inFromClient1.readObject();//read move from client 1.**//StreamCorruptedexception**

                while(!(o1 instanceof PlayerMove))
                {
                    o1=inFromClient1.readObject();//read move from client 1.
                }
                PlayerMove move1=(PlayerMove)o1;
                System.out.println("received move "+move1+" sending to "+client2.getNickname());
                outToClient2.writeObject(move1);
                System.out.println("listening to "+client2.getNickname());
                Object o2=inFromClient2.readObject();//read move from client 1.
                while(!(o2 instanceof PlayerMove))
                {   
                    o2=inFromClient2.readObject();//read move from client 1.
                }
                PlayerMove move2=(PlayerMove)o2;
                System.out.println("received move "+move2+" sending to "+client1.getNickname());
                outToClient1.writeObject(move2);
            }
                catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}
}    

метод model.addClient, хотя я не думаю, что проблема здесь

  public void addClient(String nickname, Socket       clientSocket,ObjectOutputStream stream,ObjectInputStream inStream)
{
    clients.addClient(nickname, clientSocket,stream,inStream);//add to arraylist
//send client list to all clients
    String[] users=this.getAvailableClients();
    ObjectOutputStream[] streams=clients.getOutStreams();
    for(int i=0;i<streams.length;i++)
    {
        try {
            streams[i].writeObject(users);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

Клиентский прокси, который отправляет объекты на сервер, методы запускаются действиями пользователя в графическом интерфейсе

  public class Proxy {
final int PORT = 1337;
String host;
String nickname;
private Socket clientSocket;
private ObjectOutputStream outToServer;
private ObjectInputStream inFromServer;
private ClientModelManager manager;
public Proxy(String nickname,String host,ClientModelManager manager)
{
    this.nickname=nickname;
    this.host=host;
    this.manager=manager;
    this.connect(nickname);
}
public void connect(String nick)
{
    Socket clientSocket;
    try {
        clientSocket = new Socket(host, PORT);
        System.out.println("client socket created");
        outToServer = new ObjectOutputStream(clientSocket.getOutputStream());
        inFromServer=new ObjectInputStream(clientSocket.getInputStream());
        outToServer.flush();
        outToServer.writeObject(nick);
        ClientReceiverThread t=new ClientReceiverThread(inFromServer,manager);
        t.start();
    } catch (Exception e) {
        e.printStackTrace();
    } 
}
public void makeRequest(String user)
{
    try
    {
    outToServer.writeObject(new RequestForGame(user));
    }
    catch(IOException e)
    {
        e.printStackTrace();
    }
}
public void quit()
{
    try {
        outToServer.writeObject(new String("i want to quit"));
        //clientSocket.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
public void sendMove(PlayerMove move)
{
    try {
        outToServer.writeObject(move);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

}

Хорошо. Кроме того, вы должны очистить ObjectOutputStreams после их создания, чтобы убедиться, что заголовок отправлен. Это может быть причиной того, что вы получаете эту ошибку; заголовок потока еще не прошел. Сбросьте ObjectOutputStream на клиенте и сервере после создания. Vulcan
Что делает ServerModelManager, когда вы звонитеmodel.addClient(nickname, connectionSocket,outToClient,inFromClient);? В нем может быть код, который портит поток. Vulcan
addClient (добавляет пользователя в ArrayList типа ClientRepresanative, который содержит сокет, objectouput и входной поток.) он ничего не читает user1420273
Вы не против добавить свой клиентский код туда, где вы пишете объекты? Vulcan
Я добавил промывку, ничего не изменилось user1420273

Ваш Ответ

6   ответов
1

Я недавно столкнулся с этой проблемой, не делая то же самое, что сделал OP. Сделал быстрый поиск в Google и не нашел ничего слишком полезного, и, поскольку я думаю, что решил это, я комментирую свое решение.

TLDR: не допускается, чтобы несколько потоков записывали в один и тот же выходной поток одновременно (вместо этого по очереди). Будет причиной проблем, когда клиентская сторона пытается прочитать данные. Решением является блокировка записи для вывода.

Я делаю что-то очень похожее на OP, создавая многопользовательскую (модель клиент-сервер) игру. У меня есть поток, как OP, который прослушивает трафик. То, что происходило на моей серверной стороне, заключалось в том, что на сервере было несколько потоков, которые одновременно записывали в поток клиента (не думал, что это возможно, игра была полуоборотной). Поток на стороне клиента, который считывал входящий трафик, выдавал это исключение. Чтобы решить эту проблему, я в основном установил блокировку на части, которая записывала в поток клиента (на стороне сервера), чтобы каждый поток на стороне сервера должен был получить блокировку перед записью в поток.

3

с которой я столкнулся, если вы реализуете специальную процедуру десериализации для класса, добавив этот метод:

private void readObject( ObjectInputStream objectInputStream ) throws IOException

тогда objectInputStream.defaultReadObject () должен быть вызван и вызван перед дальнейшими считываниями входного потока для правильной инициализации объекта.

Я пропустил это, и, несмотря на то, что объект возвращался без исключения, это было следующее чтение потока объекта, которое сбивало с толку недопустимое исключение кода типа.

Эта ссылка предоставляет дополнительную информацию о процессе:http://osdir.com/ml/java.sun.jini/2003-10/msg00204.html.

Исправления добавлены.
Это не правильное изложение проблемы. Проблема в том, что вы должны позвонитьdefaultReadObject(). После того, как вы сделали это, не важно, чтобы вы прочитали точное количество байтов вашего собственного материала.
3

если JVM, считывающая сериализованный объект, не имеет правильных файлов класса / jar для объекта. Это обычно приводит кClassNotFoundException, но если у вас разные версии jar / class иserialVersionUID не был изменен между версиями,StreamCorruptedException производится. (Это исключение также возможно при наличии конфликта имен классов. Например: баночка, содержащая другой класс с тем же полным именем класса, хотя им, вероятно, также необходимоserilVersionUID).

Убедитесь, что на стороне клиента установлены правильные версии файлов jar и class.

Я сделал этот ответ, поскольку я успешно исправил ошибку в вопросе, установив правильные файлы JAR. Я полагаю, что в моем случае у меня были неправильные версии (и UID версии не был должным образом поддержан), хотя это было некоторое время назад ... Это также возможно при конфликтах имен классов? @ejp Я изменю свой ответ, чтобы указать версии файлов jar - не стесняйтесь, чтобы убрать ваш отрицательный голос, это не мотивирует одного на то, чтобы предоставить другим возможность воспользоваться своим опытом!
Нет, это не может. Это условие вызывает ClassNotFoundException.
к точке @ drevicko, аналогичноhere.
К сожалению, мир не идеален, и не все поддерживаютserialVersionUIDправильно. Там не былоserialVersionUID несоответствие - это не было должным образом поддержано между версиями. Как я уже сказал, в вопросе была указана ошибка, и я решил ее, установив правильную версию. Это НЕ ошибочный диагноз! Это является возможной причиной этой ошибки.
2

что я использовал два потока для класса сервера и класса клиента. Я использовал один поток для отправки и получения объекта. Тогда это было хорошо. Это простой способ решить проблему, если вы не знакомы сsynchronized.

6

construct a new ObjectInputStream or ObjectOutputStream over the same socket instead of using the same ones for the life of the socket; use another kind of stream over the same socket as well; or, use the object streams to read or write something that isn't an object and you get out of sync.
@ user1420273 Конечно, может, если у вас нет соответствующей синхронизации.
Сначала я создаю ObjectOutputStream с обеих сторон (Proxy, ServerCommunicationThread). Я создаю его только один раз, а затем просто отправляю ссылку на него другому потоку. Я не использую любой другой вид потока. Единственное, что приходит на ум, - это то, что я пытаюсь прочитать объект из одного и того же ObjectInputStream в 2 потока одновременно. (ServerCommunicationThread, ServerGameThread) Может ли это быть проблемой? (из места исключения я бы так предположил ..) user1420273
2

ObjectInputStream создается только один раз, а затем просто передается ссылка на него другому потоку, а затем просто ограничить доступ этого объекта внутриsynchronized блок, чтобы убедиться, что только один поток может получить доступ к этому объекту одновременно.

Всякий раз, когда вы читаете изObjectInputStream просто получить доступ к нему внутриsynchronized блокировать, если он разделен между несколькими потоками.

Пример кода: (сделайте это для всех случаевreadObject())

...
String nickname = null;
synchronized (inFromClient) {
    nickname = (String) inFromClient.readObject();
}

Похожие вопросы