Wiadomości powitalne - Klient/Serwer Socket

0

Dobry wieczór. Piszę komunikator klienci-serwer. Przy połączeniu klienta do serwera, serwer wysyła mu identyfikator (ID) natomiast klient wysyła do serwera swój nick, np. Maciej (żeby potem serwer mógł rozesłać ten nick innym klientom aby widzieli tego Macieja na liście ONLINE. Czyli serwer->klient (ID) oraz klient->serwer (nick). Obie klasy Klient i Serwer (osobne aplikacje) są wykonywane jako osobne wątki. Tutaj fragment kodu:

Klasa Server programu Serwera:

public void run() { 
        int guid = 1;
        while(true) {
             try {                 
                Socket socket = server.accept();
              
                sendWelcomeMessage(socket, guid);
                getWelcomeMessage(socket, guid);       
             
             } catch(IOException e) {}
        }
    }
    
    private void sendWelcomeMessage(Socket socket, int id) {
        try {
            ObjectOutputStream onServer = new ObjectOutputStream(socket.getOutputStream());
            onServer.writeInt(id);
            //onServer.close();
        } catch(IOException e) { System.out.println("send " + e); }
    }
    
    private void getWelcomeMessage(Socket socket, int id) {
        String welcomeMsg = null;
        try
        {
            ObjectInputStream fromServer = new ObjectInputStream(socket.getInputStream());
            welcomeMsg = fromServer.readUTF(); 
            //onServer.close();
        } 
        catch(IOException e) { System.out.println("get " + e);}
     
    }

oraz kod klasy Client programu klienta:

public void run() {
        sendWelcomeMessage();
        getWelcomeMessage();   
    }
    
    private void getWelcomeMessage() {
        try {         
            ObjectInputStream fromServer = new ObjectInputStream(socket.getInputStream());
            int welcomeMsg = fromServer.readInt();
            System.out.println(welcomeMsg+"a");
            //fromServer.close();
        } 
        catch(IOException e) { System.out.println("get " + e); }
        
    }
    
    private void sendWelcomeMessage() {
         try {
            ObjectOutputStream onServer = new ObjectOutputStream(socket.getOutputStream());
            onServer.writeUTF(nickname);
            onServer.close(); // gwiazdka*
        } catch(IOException e) { System.out.println("send " + e); }       
    }

Pętla while w klasie serwera oczywiście odpowiada za to aby mogli się podłączać również inni klienci. Jak widzicie mam zakomentowane zamykanie strumieni (prócz jednego). Gdy je odkomentuje wszystko będzie działało tak samo, tzn. klient poprawnie wysyła swój nick do serwera i mogę go odczytać natomiast serwer nie wysyła ID do klienta, pojawia się wyjątek

get java.net.SocketException: Socket is closed

Natomiast wystarczy że zakomentuję linię oznaczoną jako "gwiazdka*" to program jakby się przywiesza i nic się nie dzieje - nic do siebie nie wysyłają. Jak poprawnie to zrobić żeby te wiadomości dochodziły w obie strony? Proszę o wyrozumiałość dopiero się uczę.

0

Przepraszam, gdy odkomentuję wszystkie to dużo wyjątków po prostu zwraca ;/

Serwer:

get java.net.SocketException: Socket is closed

Klient

send java.net.SocketException: Software caused connection abort: socket write error
get java.net.SocketException: Software caused connection abort: recv failed
0
  1. Masz nie zamykać połączenia po pierwszym komunikacie.
  2. Jak dwóch naraz gada to nikt nikogo nie słyszy. server: receive, send natomiast klient: send, receive owszem jak zrobiłeś może i przejdzie, ale lepiej zachować porządek.
0

To przepraszam gdzie mam zamknąć a gdzie nie, bo właśnie chyba przetestowałem wszystkie możliwe kombinacje i zawsze jakiś błąd z socketem albo jak słusznie zauważyłeś gdy mam zamknięte wszystkie to żaden się nie słyszy. Gdy jednemu zakomentuję send a drugiemu get to wysyła dobrze więc faktycznie gdzieś jest problem tego "zakleszczenia"

0

Nigdzie nie zamykasz. A run() ma mieć pętle nasłuchującą (oba). Po zakończeniu tej pętli dopiero zamykasz. Inicjatorem zamknięcia powinien być przeważnie klient, wysyła on do serwera komendę "SPADAM" i zamyka połączenie. Serwer natomiast ma zamknąć po odebraniu komendy "SPADAM".

0

Początkowo miałem z pętlą ale średnio działało więc doszedłem do wniosku że jeżeli mam wysłać tylko jedną wiadomość to wystarczy raz wysłać bez pętli i odebrać tak jak to jest prezentowane w tutorialach. Czyli mam zrobić po stronie serwera i klienta pętlę nieskończoną i przerwać ją gdy otrzymam wiadomość? W pętli cały czas wysyłać wiadomość powitalną i sprawdzać czy odebrano?

1 użytkowników online, w tym zalogowanych: 0, gości: 1