Witam.

Piszę prosty komunikator internetowy. Serwer odpala jeden wątek dla każdego połączenia, w którym obsługuje zarówno wysyłanie, jak i odbieranie wiadomości. Zależnie od treści odpowiedniego pola serializowanej klasy Message decyduje, co dalej począć z odebraną od klienta wiadomością. Natomiast klient w momencie zalogowania na serwer uruchamia wątek główny, który odpowiada za tworzenie dwóch wątków: odbierającego i wysyłającego, automatycznie wysyła na serwer Message z danymi klienta do zalogowania, a później pośredniczy w przekazywaniu temu ostatniemu kolejnych wiadomości z GUI klienta (ConcurrentLinkedQueue).

Mam problem ze skoordynowaniem działania obiektów klas ObjectOutputStream i ObjectInputStream. Wyrzuca mi błąd java.io.StreamCorruptedException: invalid type code: AC ze wskazaniem na metody readObject() po obu stronach socketa. Ten sam błąd wyskakuje przy transmisji zwykłego Stringa, więc tu raczej nie leży przyczyna...

Podejrzewam, że wynika to z faktu, iż wątek odpowiedzialny za wysyłkę iteruje się wielokrotnie próbując nadpisywać outputStream, podczas gdy wątek nasłuchujący bezczynnie czeka z inputStreamem na nadejście obiektu. Co ciekawe, za pierwszym razem wszystko jest w porządku: klient poprawnie zalogowuje się na serwerze, a ten umieszcza jego dane w odpowiednim HashSecie i odsyła klientowi powitalną wiadomość, która wyświetla się w okienku tego ostatniego. Próbowałem inicjalizować output i input w różnych miejscach, ale nigdy nie dało to pożądanego rezultatu. Co zatem robię źle?

Metoda run wątka wysyłającego po stronie klienta:

  public void run() {
        try {
           this.output = new ObjectOutputStream(this.socket.getOutputStream());
           this.output.flush();
            while(true) {
                if(this.messageQueue.isEmpty()) continue;
                this.message = this.messageQueue.poll();                        
                if(this.message == null) {
                    continue;
                } else {
                    this.output.writeObject(this.message);
                    this.output.flush();
                    this.message = null;
                }
            }
        } catch(IOException ioex) {
            ioex.printStackTrace();
        }
    } 

Metoda run wątka odbierającego po stronie klienta. W ramach wyjaśnienia: wiadomość odbierana przez klienta może mieć nagłówek "Online" - to oznacza, że zawiera ona obiekt typu HashSet<String> z listą zalogowanych klientów. W przeciwnym wypadku jest to zwykła wiadomość, która zostaje wypisana w okienku GUI:

 public void run() {
        try {
            this.input = new ObjectInputStream(this.socket.getInputStream());
            while(true) {
                this.message = (Message) input.readObject();
                if(this.message.getText().equals("Online")) {
                    this.usersOnline = null;
                    this.usersOnline = this.message.getUsersOnline();
                    this.client.usersOnlineUpdate(this.usersOnline);
                } else {
                    this.client.setText(this.message.getName() + ": "
                            + this.message.getText());
                }
                this.message = null;
            }
        } catch(IOException ioex) {
            ioex.printStackTrace();
        } catch(ClassNotFoundException cnfex) {
            cnfex.printStackTrace();
        }
    }

Metoda run wątka po stronie serwera:

    public void run() {
        try {
            this.input = new ObjectInputStream(socket.getInputStream());
            this.output = new ObjectOutputStream(socket.getOutputStream());
            while(true) {
                this.receivedMessage = (Message) this.input.readObject();
                this.name = this.receivedMessage.getName();

                if(this.receivedMessage.getInterlocutor().equals("Server")) {
                    if(this.receivedMessage.getText().equals("whois")) {
                        onlineUsers();
                        continue;
                    }
                    if(this.receivedMessage.getText().equals("quits")) {
                        logOutUser();
                    }
                    if(this.receivedMessage.getText().equals("connect")) {
                        System.out.println("run(if connect!)");
                         logInUser();
                    }
                }
            }
        }  catch(ClassNotFoundException cnfex) {
            this.server.setText("Błąd: " + cnfex);
        }  catch(IOException ioex) {
            this.server.setText("Błąd: " + ioex);
        }
    }

    private void logInUser() {
        // dodawanie logującego się użytkownika do listy zalogowanych
        if(!this.server.getUsersOnline().contains(this.receivedMessage.getName())) {
             this.server.addUser(this.receivedMessage.getName());
        }
        this.name = this.receivedMessage.getName();
        // wysyłanie wiadomości powitalnej
        this.sentMessage = new Message("Serwer", "Witaj w RS Communicator!");
        this.server.setText(this.sentMessage.getName() + ": " +
                this.sentMessage.getText());
        this.send(sentMessage);
    }

    private void onlineUsers() {
        // wysyłanie klientowi listy zalogowanych użytkowników
        this.sentMessage = new Message("Server", "Online",
                new HashSet <String>(this.server.getUsersOnline()));
        this.send(sentMessage);
    }

    private void send(Message message) {
        try {            
            this.output.writeObject((Message) message);            
            this.output.flush();
        } catch(IOException ioex) {
            ioex.printStackTrace();
        }
    }

Byłbym wdzięczny za wszelkie porady.