Java gnizada(socket) - rozłączanie, połączenia nieblokujące

0

Witam.

Chciałbym napisać prosty komunikator sieciowy. Używam połączeń blokujących. Sytuacja wygląda tak: klient przesyła serwerowi wiadomość a ten odpowiada (międzyczasie klient czeka)
Jeżeli klient chciałby dopisać jakąś wiadomość musi czekać aż serwer odpowie, w przeciwnym wypadku jest zablokowany. Wypadałoby oczekiwać w nowym wątku na odbieranie wiadomości.
A jak zrobić to metodą nieblokującą?
Kolejna sprawa to wykrywanie rozłączenia połączenia.
Jak prawidłowo się rozłączyć z serwerem (lub na odwrót), żeby to wykrył. Są metody w socet (teoretycznie) umożliwiające sprawdzenie (is connected itd.). Jednak u mnie nie działają.
Jak sprawdzić połączenia, strumienie. Jak przy zamknięciu klienta serwer ma odebrać tą informację (szczególnie w przypadku awarii klienta, lub niespowadziewanego rozłączenia.

Napisałem taki kodzik. Serwer jest wielowątkowy.

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
 
public class Server {
 
    private ArrayList threadList;
    public int nr;
    
    public Server() {
        this.nr = 0;
        this.threadList = new ArrayList(0);
        
        try {

            ServerSocket serverSocket = new ServerSocket(9090);

            while (true) {
                Socket socket = serverSocket.accept();
                InputStream is = socket.getInputStream();
                OutputStream os = socket.getOutputStream();
                
                this.nr++;
                System.out.println("::: CONNECT: "+this.nr);

                ThreadServer thread= new ThreadServer(socket, this, this.nr, is, os);
                thread.start();
                this.threadList.add(thread);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                for (int i = 0; i < threadList.size(); i++) {
                    ThreadSpecial thread = (ThreadSpecial) threadList.get(i);
                    System.out.println("::: Server work: "+thread.isAlive());
                    thread.close();
                }
            } catch(Exception e) {
            }
        }
    }
 
    public static void main(String[] args) {
        new Server();
    }
}

Wątek serwera

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;


public class ThreadServer extends Thread {

    public Server server; 
    
    public Socket socket;
    public InputStream is;
    public OutputStream os;
    
    public int nr;
    
    public ThreadServer(Socket socket, Server server, int nr, InputStream is, OutputStream os) {
        this.server = server;
        
        this.socket = socket;
        this.is = is;
        this.os = os;
        
        this.nr = nr;
    }
    
    @Override
    public void run() {

            while(true) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException ex) {
                    Logger.getLogger(ThreadServer.class.getName()).log(Level.SEVERE, null, ex);
                }
                synchronized(this) {
                    try {
                        //InputStream is = socket.getInputStream();
                        InputStreamReader isr = new InputStreamReader(is);
                        BufferedReader br = new BufferedReader(isr);
                        String number = br.readLine();

                        System.out.println("... "+this.nr+" Wiadomość od klienta: "+number);

                        String returnMessage;

                        try {
                            int numberInIntFormat = Integer.parseInt(number);
                            int returnValue = numberInIntFormat*2;
                            returnMessage = String.valueOf(returnValue) + "\n";
                        } catch(NumberFormatException e) {
                            returnMessage = "Wprowadź prawidłową liczbę\n";
                        }

                        //OutputStream os = this.socket.getOutputStream();
                        OutputStreamWriter osw = new OutputStreamWriter(os);
                        BufferedWriter bw = new BufferedWriter(osw);
                        bw.write(returnMessage+" mada faka");
                        System.out.println(">>> "+this.nr+" Do klienta: "+returnMessage);//returnMessage);
                        bw.flush();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }    
                }
            }

    }
        
    public void closeBude() {
        try {
            System.out.println("BUDA");
            this.socket.close();
        } catch (IOException ex) {
            Logger.getLogger(ThreadServer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}


Klient

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
 
public class Client {
 
    private static Socket socket;
 
    public Client() throws IOException {
        try {
            this.socket = new Socket("localhost", 9090);
            System.out.println("Klient...");
            
            while(true) {
                OutputStream os = socket.getOutputStream();
                OutputStreamWriter osw = new OutputStreamWriter(os);
                BufferedWriter bw = new BufferedWriter(osw);

                Scanner scanner = new Scanner(System.in);
                String number = scanner.nextLine();
                if ("123".equals(number)) {
                    bw.close();
                    osw.close();
                    os.close();
                    
                    break;
                }

                //String number = "2";
                System.out.println("Input: "+socket.isInputShutdown());
                System.out.println("Output: "+socket.isInputShutdown());                
                String sendMessage = number + "\n";
                bw.write(sendMessage);
                bw.flush();
                System.out.println("[>]Wiadomość dla serwera : "+sendMessage);

                InputStream is = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                String message = br.readLine();
                System.out.println("[<]Wiadomość od serwera : " +message);
            }
            socket.shutdownInput();
            socket.shutdownOutput();
            Close();
        } catch (Exception exception) {
            System.out.println("!!! Błąd kodu");
            socket.shutdownInput();
            socket.shutdownOutput();
            Close();            
            exception.printStackTrace();
        } finally {
            try {
                if (socket.isConnected()) {
                   // socket.shutdownInput();
                 //   socket.shutdownOutput();                
                    socket.close();
                }
            } catch(Exception e) {
                System.out.println("!!! Błąd zamykania gniazda");
                e.printStackTrace();
            }
        }  
    }
    
    public void Close() {
        try {
            socket.close();
        } catch (IOException ex) {
            System.out.println("!!! Błąd zamykania gniazda in Close");
           // Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
    }    
    
    public static void main(String args[]) {
        try {
            new Client();
        } catch (IOException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
0

->UDP DatagramSocket ; nie gwarantuje dotarcia pakietu

?> Kolejna sprawa to wykrywanie rozłączenia połączenia" ->Rzucanie wyjątku jeżeli socket(połaczenie) przed zakończeniem wymiany zostanie zamknięt).
?>" Jak prawidłowo się rozłączyć z serwerem (lub na odwrót), żeby to wykrył." -> Po wymianie danych zamknięcie strumieni następnie połaczenia.
?>" Jak sprawdzić połączenia, strumienie. Jak przy zamknięciu klienta serwer ma odebrać tą informację (szczególnie w przypadku awarii klienta, lub niespowadziewanego rozłączenia."
->Powinien rzucić wyjatek , możesz też ustawić timeout dla socketa

title

0

A jak zrobić to metodą nieblokującą?

jesli musi byc na czystych socketach to popatrz w okolicach nio.

Kolejna sprawa to wykrywanie rozłączenia połączenia.
Jak prawidłowo się rozłączyć z serwerem (lub na odwrót), żeby to wykrył.

po prostu close() na sockecie i serwer zauwazy.

Jak sprawdzić połączenia, strumienie. Jak przy zamknięciu klienta serwer ma odebrać tą informację (szczególnie w przypadku awarii klienta, lub niespowadziewanego rozłączenia.

zalezy od api. szczegolow nio nie pamietam ale z duzym prawdopodobienstwem api stwierdzi ze moze czytac a przy probie odczytu bedzie zwrocone -1. tyle ze w praktyce to za malo dlatego ze czasami sockety znikaja nie informujac o tym serwera. dlatego protokol sieciowy powinien gwarantowac ze co jakis czas beda przysylane komunikaty zeby serwer mogl posprzatac po padnietych klientach. jesli to nie wynika naturalnie z aplikacji to trzeba dodac jakies pingi do protokolu. albo po prostu rozlaczac jesli klient przez dluzszy czas nie ma nic do powiedzednia. inna opcja poza pingami to ustawienie na sockecie keep alive. tyle ze z tego co pamietam to minimalny czas po ktorym keep alive spowoduje ze serwer zauwazy ze klient padl to chyba ok. 2h - paskudnie dlugo.

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