Shkrimi i softuerit me funksionalitetin e utilitarëve klient-server Windows, pjesa 01.

Përshëndetje.

Sot dysh, do tĂ« flasim pĂ«r procesin e shkruarjes sĂ« aplikacioneve klient-server qĂ« kryejnĂ« funksionet e utiliteteve standarde tĂ« Windows, si Telnet, TFTP, etj., etj., nĂ« JavĂ«n e pastĂ«r. ËshtĂ« e qartĂ« se nuk do tĂ« sjell asgjĂ« tĂ« re — tĂ« gjitha kĂ«to utilitete tashmĂ« funksionojnĂ« me sukses pĂ«r njĂ« kohĂ« tĂ« gjatĂ«, por, besoj se nuk tĂ« gjithĂ« e dinĂ« se çfarĂ« ndodh nĂ«n kapakĂ«t e tyre.

Sikurse flitet për këtë në vazhdim.

NĂ« kĂ«tĂ« artikull, pĂ«r tĂ« mos e çekur, pĂ«rveç informacionit tĂ« pĂ«rgjithshĂ«m, do tĂ« shkruaj vetĂ«m pĂ«r serverin Telnet, por aktualisht ka edhe materiale pĂ«r utilitete tĂ« tjera — ato do tĂ« jenĂ« nĂ« pjesĂ«t e ardhshme tĂ« ciklit.

SĂ« pari, duhet tĂ« kuptojmĂ« se çfarĂ« Ă«shtĂ« Telnet, pĂ«r çfarĂ« Ă«shtĂ« i nevojshĂ«m dhe si e pĂ«rdorim. Nuk do tĂ« citoj fjalĂ« pĂ«r fjalĂ« burimet (nĂ«se Ă«shtĂ« e nevojshme — nĂ« fund tĂ« artikullit do tĂ« bashkĂ«ngjitet njĂ« lidhje pĂ«r materialet mbi temĂ«n), do tĂ« them vetĂ«m se Telnet siguron akses tĂ« largĂ«t nĂ« komandĂ«n e pajisjes. NĂ« thelb, kĂ«tu pĂ«rfundon funksionaliteti i tij (pĂ«r pĂ«rdorimin e portit tĂ« serverit do tĂ« mbaj nĂ« heshtje pĂ«r momentin, pĂ«r kĂ«tĂ« mĂ« vonĂ«). KĂ«shtu qĂ«, pĂ«r zbatimin e tij, na nevojitet tĂ« pranojmĂ« njĂ« varg nĂ« klient, ta transferojmĂ« atĂ« nĂ« server, tĂ« pĂ«rpiqemi ta dĂ«rgojmĂ« nĂ« komandĂ«n tuaj, tĂ« marrim pĂ«rgjigjen e komandĂ«s, nĂ«se ka, ta transferojmĂ« pĂ«rsĂ«ri nĂ« klient dhe ta shfaqim nĂ« ekran, ose, nĂ« rast tĂ« ndonjĂ« gabimi, t'i bĂ«jmĂ« tĂ« qartĂ« pĂ«rdoruesit se diçka nuk shkon.

Për realizimin e të përmendurve më sipër, nevojiten përkatësisht 2 klasa funksionale dhe një klasë testuese, nga e cila do të fillojmë serverin dhe përmes së cilës do të punojmë me klientin.
Përkatësisht, struktura aktuale e aplikacionit përfshin:

  • TelnetClient
  • TelnetClientTester
  • TelnetServer
  • TelnetServerTester

Do të kalojmë nëpër secilën prej tyre:

TelnetClient

E gjitha çfarĂ« duhet tĂ« jetĂ« nĂ« gjendje tĂ« bĂ«jĂ« kjo klasĂ« — tĂ« dĂ«rgojĂ« komandat e marra dhe tĂ« tregojĂ« pĂ«rgjigjet e marra. PĂ«r mĂ« tepĂ«r, duhet tĂ« jetĂ« nĂ« gjendje tĂ« lidhĂ« me njĂ« port tĂ« rastĂ«sishĂ«m (siç e thashĂ« mĂ« sipĂ«r) tĂ« pajisjes sĂ« largĂ«t dhe tĂ« shkĂ«putet prej tij.

Për këtë janë realizuar funksionet e mëposhtme:

NjĂ« funksion qĂ« pranon si argument adresĂ«n e socket-it, hap lidhjen dhe aktivizon rrjedhat e hyrjes dhe daljes (variablat e rrjedhĂ«s janĂ« shpallur mĂ« sipĂ«r, kodet e plota — nĂ« fund tĂ« artikullit).

 publik void run(String ip, int port)
    {
        përpiqem {
            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();
        }
        kapur (Përjashtim e) {
            System.out.println(e.getMessage());
        }
    }

Overload i kĂ«saj funksioni, qĂ« lidhet me portin e paracaktuar — pĂ«r telnetin Ă«shtĂ« 23


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

Funksioni lexon karakteret nga tastiera dhe i dĂ«rgon nĂ« soketin e daljes — siç Ă«shtĂ« tipike, nĂ« modin e linjĂ«s, dhe jo nĂ« modin e karaktereve:


    private void read(Scanner keyboard, OutputStream sout)
    {
        përpiqem {
            String input = new String();
            ndërsa (e vërtetë) {
                input = keyboard.nextLine();
                për (char i : (input + " n").toCharArray())
                    sout.write(i);
            }
        }
        kapur (Përjashtim e) {
            System.out.println(e.getMessage());
        }
    }

Funksioni merr të dhëna nga soketi dhe i shfaq ato në ekran


    private void write(InputStream sin)
    {
        përpiqem {
            int tmp;
            ndërsa (e vërtetë){
                tmp = sin.read();
                System.out.print((char)tmp);
            }
        }
        kapur (Përjashtim e) {
            System.out.println(e.getMessage());
        }
    }

Funksioni ndalon marrjen dhe dërgimin e të dhënave


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

TelnetServer

Ky klas duhet të ketë funksionalitetin e pranimit të komandës nga soketi, dërgimin e saj për egzekutim dhe dërgimin e përgjigjes nga komanda përsëri në soket. Në program qëllimisht nuk ka verifikim të të dhënave hyrëse, sepse së pari, dhe në "telnetin e kutisë" ekziston mundësia për të formatuar diskun e serverit, dhe së dyti, çështja e sigurisë në këtë artikull është lënë jashtë dhe për këtë arsye nuk ka asnjë fjalë për enkriptimin ose SSL.

Këtu ka vetëm 2 funksione (njëra prej të cilave është overload), dhe në përgjithësi kjo nuk është një praktikë shumë e mirë, megjithatë në kuadër të kësaj detyre më duket e arsyeshme ta lë gjithçka ashtu siç është.

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

        (new Thread(()->{ try {
            ServerSocket ss = new ServerSocket(port); // krijojmë soket serveri dhe e lidhim atë me portin e mësipërm
            System.out.println("Port " + port + " është duke pritur për lidhje");

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

            // Marrim rrjedhat hyrëse dhe dalëse të soketit, tani mund të marrim dhe dërgojmë të dhëna klientit.
            InputStream sin = socket.getInputStream();
            OutputStream sout = socket.getOutputStream();

            Map 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 = "Diçka shkoi keq... Kodi i gabimit: " + 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("Gabim: " + e.getMessage());
                    }
                }).start();
                System.out.println(buffer);
                buffer = "";

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

    }

Programi hap një port serveri, lexon nga të dhënat derisa të takohet simboli përfundimtar i komandës, transferon komandën në një proces të ri, dhe dalja nga procesi është ridrejtuar në soket. E thjeshtë si një automat Kalashnikovi.

Prandaj, për këtë funksion ka një mbushje me portin e paracaktuar:

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

Po ashtu, funksioni qĂ« ndalon serverin — gjithashtu Ă«shtĂ« e thjeshtĂ«, ai ndĂ«rpret ciklin e pĂ«rhershĂ«m, duke shkelur kushtin e tij.

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

Nuk i sjell kĂ«tu klasat testuese, ato janĂ« mĂ« poshtĂ« — gjithçka qĂ« ato bĂ«jnĂ« Ă«shtĂ« tĂ« kontrollojnĂ« funksionalitetin e metodave publike. TĂ« gjitha janĂ« nĂ« Git.

PĂ«rmbledhur, pĂ«r disa mbrĂ«mje mund tĂ« kuptoni parimet e veprimit tĂ« utiliteteve kryesore tĂ« konsolĂ«s. Tani, kur ne lidhemi me njĂ« kompjuter tĂ« largĂ«t, ne kuptojmĂ« se çfarĂ« po ndodh — magia ka ikur)

Pra, lidhjet:
Të gjitha burimet kanë qenë, janë dhe do të jenë këtu
Për Telnetin
Më shumë për Telnetin

Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster