Scrittura di software cù e funziunalità di l'utilità client-server Windows, parte 01

Saluti.

Oghje vogliu vede u prucessu di scrittura di l'applicazioni client-server chì eseguisce e funzioni di l'utilità standard di Windows, cum'è Telnet, TFTP, et cetera, et cetera in pura Java. Hè chjaru chì ùn aghju micca purtatu nunda di novu - tutte queste utilità anu travagliatu cù successu per più di un annu, ma crede chì micca tutti sapi ciò chì passa sottu u cappucciu.

Questu hè esattamente ciò chì serà discutitu sottu u cut.

In questu articulu, per ùn trascinà micca, in più di l'infurmazioni generale, scriveraghju solu nantu à u servitore Telnet, ma à u mumentu ci hè ancu materiale nantu à altre utilità - serà in più parti di a serie.

Prima di tuttu, avete bisognu di capisce ciò chì Telnet hè, ciò chì hè necessariu, è ciò chì hè utilizatu. Ùn citeraghju micca e fonti verbatim (se necessariu, aghjustà un ligame à i materiali nantu à u tema à a fine di l'articulu), diceraghju solu chì Telnet furnisce l'accessu remoto à a linea di cummanda di u dispusitivu. In generale, questu hè induve a so funziunalità finisce (aghju deliberatamente tenutu silenziu annantu à l'accessu à u portu di u servitore; più nantu à questu dopu). Questu significa chì per implementà, avemu bisognu di accettà una linea nantu à u cliente, passà à u servitore, pruvate di passà à a linea di cummanda, leghjite a risposta di a linea di cumanda, se ci hè una, passala torna à u cliente è mostrallu nantu à u screnu, o, in casu d'errore, fate à l'utilizatori sapè chì qualcosa hè sbagliatu.

Per implementà u sopra, per quessa, avemu bisognu di classi di travagliu 2 è una classe di teste da quale lanciaremu u servitore è attraversu quale u cliente hà da travaglià.
Dunque, in u mumentu, a struttura di l'applicazione include:

  • TelnetClient
  • TelnetClientTester
  • TelnetServer
  • TelnetServerTester

Passemu per ognunu di elli:

TelnetClient

Tuttu sta classa deve esse capace di fà hè di mandà cumandamenti ricevuti è mostra e risposte ricevute. Inoltre, avete bisognu di pudè cunnette à un portu arbitrariu (cum'è chjamatu sopra) di un dispositivu remoto è disconnect da ellu.

Per ottene questu, sò state implementate e seguenti funzioni:

Una funzione chì piglia un indirizzu di socket cum'è argumentu, apre una cunnessione è principia i flussi di input è output (variabili di flussu sò dichjarati sopra, i fonti cumpleti sò à a fine di l'articulu).

 public void run(String ip, int port)
    {
        try {
            Socket socket = new Socket(ip, port);
            InputStream sin = socket.getInputStream();
            OutputStream sout = socket.getOutputStream();
            Scanner keyboard = new Scanner(System.in);
            reader = new Thread(()->read(keyboard, sout));
            writer = new Thread(()->write(sin));
            reader.start();
            writer.start();
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

Overloading a stessa funzione, cunnette à u portu predeterminatu - per telnet questu hè 23


    public void run(String ip)
    {
        run(ip, 23);
    }

A funzione leghje caratteri da u teclatu è li manda à u socket di output - chì hè tipicu, in modu di linea, micca in modu di caratteri:


    private void read(Scanner keyboard, OutputStream sout)
    {
        try {
            String input = new String();
            while (true) {
                input = keyboard.nextLine();
                for (char i : (input + " n").toCharArray())
                    sout.write(i);
            }
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

A funzione riceve dati da u socket è mostra nantu à u screnu


    private void write(InputStream sin)
    {
        try {
            int tmp;
            while (true){
                tmp = sin.read();
                System.out.print((char)tmp);
            }
        }
        catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

A funzione ferma a ricezione è a trasmissione di dati


    public void stop()
    {
        reader.stop();
        writer.stop();
    }
}

TelnetServer

Questa classa deve avè a funziunalità di riceve un cumandamentu da un socket, mandendu per l'esekzione, è mandà una risposta da u cumandamentu à u socket. U prugramma deliberatamente ùn cuntrolla micca i dati di input, perchè prima, ancu in "telnet boxed" hè pussibule formate u discu di u servitore, è in segundu, u prublema di sicurità in questu articulu hè omessa in principiu, è per quessa ùn ci hè micca. una parolla nantu à a criptografia o SSL.

Ci hè solu 2 funzioni (una d'elli hè overloaded), è in generale questu ùn hè micca una pratica assai bona, ma per i scopi di questu compitu, mi pareva adattatu per lascià tuttu ciò chì hè.

 boolean isRunning = true;
    public void run(int port)    {

        (new Thread(()->{ try {
            ServerSocket ss = new ServerSocket(port); // создаем сокет сервера и привязываем его к вышеуказанному порту
            System.out.println("Port "+port+" is waiting for connections");

            Socket socket = ss.accept();
            System.out.println("Connected");
            System.out.println();

            // Берем входной и выходной потоки сокета, теперь можем получать и отсылать данные клиенту.
            InputStream sin = socket.getInputStream();
            OutputStream sout = socket.getOutputStream();

            Map<String, String> env = System.getenv();
            String wayToTemp = env.get("TEMP") + "tmp.txt";
            for (int i :("Connectednnr".toCharArray()))
                sout.write(i);
            sout.flush();

            String buffer = new String();
            while (isRunning) {

                int intReader = 0;
                while ((char) intReader != 'n') {
                    intReader = sin.read();
                    buffer += (char) intReader;
                }


                final String inputToSubThread = "cmd /c " + buffer.substring(0, buffer.length()-2) + " 2>&1";


                new Thread(()-> {
                    try {

                        Process p = Runtime.getRuntime().exec(inputToSubThread);
                        InputStream out = p.getInputStream();
                        Scanner fromProcess = new Scanner(out);
                        try {

                            while (fromProcess.hasNextLine()) {
                                String temp = fromProcess.nextLine();
                                System.out.println(temp);
                                for (char i : temp.toCharArray())
                                    sout.write(i);
                                sout.write('n');
                                sout.write('r');
                            }
                        }
                        catch (Exception e) {
                            String output = "Something gets wrong... Err code: "+ e.getStackTrace();
                            System.out.println(output);
                            for (char i : output.toCharArray())
                                sout.write(i);
                            sout.write('n');
                            sout.write('r');
                        }

                        p.getErrorStream().close();
                        p.getOutputStream().close();
                        p.getInputStream().close();
                        sout.flush();

                    }
                    catch (Exception e) {
                        System.out.println("Error: " + e.getMessage());
                    }
                }).start();
                System.out.println(buffer);
                buffer = "";

            }
        }
        catch(Exception x) {
            System.out.println(x.getMessage());
        }})).start();

    }

U prugramma apre u portu di u servitore, leghje e dati da ellu finu à chì scontra un caratteru di fine di cumandamentu, passa u cumandamentu à un novu prucessu, è redirige l'output da u prucessu à u socket. Tuttu hè simplice cum'è un fucile d'assaltu Kalashnikov.

Per quessa, ci hè una sovraccarica per sta funzione cù un portu predeterminatu:

 public void run()
    {
        run(23);
    }

Eppo, per quessa, a funzione chì ferma u servitore hè ancu triviale, interrompe u ciclu eternu, violendu a so cundizione.

    public void stop()
    {
        System.out.println("Server was stopped");
        this.isRunning = false;
    }

Ùn daraghju micca classi di teste quì, sò quì sottu - tuttu ciò chì facenu hè di verificà a funziunalità di i metudi publichi. Tuttu hè nantu à u git.

Per sintetizà, in un paru di serate pudete capisce i principii di u funziunamentu di e utilità principali di a consola. Avà, quandu telenet à un computer remoto, capiscenu ciò chì succede - a magia hè sparita)

Allora, i ligami:
Tutte e fonti eranu, sò è seranu quì
À propositu di Telnet
Più nantu à Telnet

Source: www.habr.com

Add a comment