Nggawe piranti lunak kanthi fungsi utilitas client-server Windows, bagean 02

Nerusake seri artikel sing dikhususake kanggo implementasi khusus utilitas konsol Windows Ora mungkin ora nyebutake TFTP (Trivial File Transfer Protocol) - protokol transfer file sing prasaja.

Minangka pungkasan, ayo goleki teori kasebut kanthi ringkes, deleng kode sing ngetrapake fungsi sing padha karo sing dibutuhake, lan analisa. Rincian liyane - ing sangisore potong

Aku ora bakal nyalin-tempel informasi referensi, pranala sing bisa ditemokake kanthi tradisional ing pungkasan artikel, aku mung bakal ngomong yen ing inti, TFTP minangka variasi sing disederhanakake saka protokol FTP, ing ngendi setelan kontrol akses. wis dibusak, lan nyatane ora ana apa-apa ing kene kajaba prentah kanggo nampa lan nransfer file. Nanging, supaya implementasine kita rada elegan lan dicocogake karo prinsip nulis kode saiki, sintaks wis rada diganti - iki ora ngganti prinsip operasi, nanging antarmuka, IMHO, dadi sethitik liyane logis lan nggabungake aspek positif saka FTP lan TFTP.

Utamane, nalika diluncurake, klien njaluk alamat IP server lan port ing ngendi TFTP khusus mbukak (amarga ora kompatibel karo protokol standar, aku nganggep manawa cocog kanggo ninggalake pangguna kanggo milih port), sawise iku sambungan occurs, minangka asil saka klien bisa ngirim salah siji saka printah - njaluk utawa sijine, kanggo nampa utawa ngirim file menyang server. Kabeh file dikirim ing mode binar kanggo nyederhanakake logika.

Kanggo ngleksanakake protokol, aku biasane nggunakake 4 kelas:

  • TFTPClient
  • TFTPServer
  • TFTPClientTester
  • TFTPServerTester

Amarga kasunyatan manawa kelas tes mung ana kanggo debugging sing utama, aku ora bakal nganalisa, nanging kode kasebut bakal ana ing repositori kasebut bisa ditemokake ing pungkasan artikel. Saiki aku bakal katon ing kelas utama.

TFTPClient

Tugas kelas iki yaiku nyambungake menyang server remot nggunakake nomer ip lan porte, maca printah saka stream input (ing kasus iki, keyboard), parse, transfer menyang server, lan gumantung apa sampeyan kudu ngirim utawa nampa file, nransfer utawa njaluk.

Kode kanggo mbukak klien kanggo nyambung menyang server lan ngenteni printah saka stream input katon kaya iki. Sawetara variabel global sing digunakake ing kene diterangake ing njaba artikel kasebut, ing teks lengkap program kasebut. Amarga ora pati penting, aku ora nyebutake supaya ora kakehan artikel kasebut.

 public void run(String ip, int port)
    {
        this.ip = ip;
        this.port = port;
        try {
            inicialization();
            Scanner keyboard = new Scanner(System.in);
            while (isRunning) {
                getAndParseInput(keyboard);
                sendCommand();
                selector();
                }
            }
        catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

Ayo goleki metode sing diarani ing blok kode iki:

Ing kene file kasebut dikirim - nggunakake pemindai, kita nampilake isi file kasebut minangka array byte, sing kita tulis siji-siji menyang soket, banjur ditutup lan mbukak maneh (dudu solusi sing paling jelas, nanging iku njamin release saka sumber daya), sawise kang kita nampilake pesen bab transfer sukses.

private  void put(String sourcePath, String destPath)
    {

        File src = new File(sourcePath);
        try {

            InputStream scanner = new FileInputStream(src);
            byte[] bytes = scanner.readAllBytes();
            for (byte b : bytes)
                sout.write(b);
            sout.close();
            inicialization();
            System.out.println("nDonen");
            }

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

Fragmen kode iki nggambarake njupuk data saka server. Kabeh maneh ora pati penting, mung blok pertama kode sing menarik. Supaya ngerti persis carane akeh bita kudu diwaca saka soket, sampeyan kudu ngerti carane akeh file ditransfer bobot. Ukuran berkas ing server diwakili minangka integer sing dawa, mula 4 bait ditampa ing kene, sing banjur diowahi dadi siji nomer. Iki ora pendekatan Jawa banget, iku rodo padha kanggo SI, nanging solves masalah sawijining.

Banjur kabeh iku ora pati penting - kita nampa nomer dikenal saka bita saka soket lan nulis menyang file, sawise kang kita nampilake pesen sukses.

   private void get(String sourcePath, String destPath){
        long sizeOfFile = 0;
        try {


            byte[] sizeBytes = new byte[Long.SIZE];
           for (int i =0; i< Long.SIZE/Byte.SIZE; i++)
           {
               sizeBytes[i] = (byte)sin.read();
               sizeOfFile*=256;
               sizeOfFile+=sizeBytes[i];
           }

           FileOutputStream writer = new FileOutputStream(new File(destPath));
           for (int i =0; i < sizeOfFile; i++)
           {
               writer.write(sin.read());
           }
           writer.close();
           System.out.println("nDONEn");
       }
       catch (Exception e){
            System.out.println(e.getMessage());
       }
    }

Yen prentah liyane saka njaluk utawa dilebokake ing jendela klien, fungsi showErrorMessage bakal diarani, nuduhake yen input kasebut salah. Amarga triviality, aku ora bakal ngutip. Luwih menarik yaiku fungsi nampa lan pamisah string input. We pass scanner menyang, saka kang kita ngarepake kanggo nampa baris dipisahake dening rong spasi lan ngemot printah, alamat sumber lan alamat tujuan.

    private void getAndParseInput(Scanner scanner)
    {
        try {

            input = scanner.nextLine().split(" ");
            typeOfCommand = input[0];
            sourcePath = input[1];
            destPath = input[2];
        }
        catch (Exception e) {
            System.out.println("Bad input");
        }
    }

Ngirim printah - ngirim printah sing dilebokake saka scanner menyang soket lan meksa supaya dikirim

    private void sendCommand()
    {
        try {

            for (String str : input) {
                for (char ch : str.toCharArray()) {
                    sout.write(ch);
                }
                sout.write(' ');
            }
            sout.write('n');
        }
        catch (Exception e) {
            System.out.print(e.getMessage());
        }
    }

Selector minangka fungsi sing nemtokake tumindak program gumantung saka string sing dilebokake. Kabeh ing kene ora apik banget lan trik sing digunakake dudu sing paling apik kanthi metu paksa ing njaba blok kode, nanging alasan utama yaiku ora ana ing Jawa sawetara perkara, kaya delegasi ing C #, penunjuk fungsi saka C ++, utawa ing paling goto elek lan elek, sing ngijini sampeyan kanggo ngleksanakake iki apik. Yen sampeyan ngerti carane nggawe kode sethitik liyane elegan, Aku welcome kritik ing komentar. Kayane aku butuh kamus String-delegate ing kene, nanging ora ana utusan ...

    private void selector()
    {
        do{
            if (typeOfCommand.equals("get")){
                get(sourcePath, destPath);
                break;
            }
            if (typeOfCommand.equals("put")){
                put(sourcePath, destPath);
                break;
            }
            showErrorMessage();
        }
        while (false);
    }
}

TFTPServer

Fungsi server beda karo fungsi klien, umume, mung ing printah kasebut ora saka keyboard, nanging saka soket. Sawetara cara umume padha, mula aku ora bakal nyebutake, aku mung bakal ndemek bedane.

Kanggo miwiti, cara roto digunakake, sing nampa port minangka input lan ngolah data input saka soket ing daur ulang langgeng.

    public void run(int port) {
            this.port = port;
            incialization();
            while (true) {
                getAndParseInput();
                selector();
            }
    }

Metode put, sing mbungkus metode writeToFileFromSocket sing mbukak stream nulis menyang file lan nulis kabeh bait input saka soket, nampilake pesen sing nuduhake sukses transfer nalika nulis rampung.

    private  void put(String source, String dest){
            writeToFileFromSocket();
            System.out.print("nDonen");
    };
    private void writeToFileFromSocket()
    {
        try {
            FileOutputStream writer = new FileOutputStream(new File(destPath));
            byte[] bytes = sin.readAllBytes();
            for (byte b : bytes) {
                writer.write(b);
            }
            writer.close();
        }
        catch (Exception e){
            System.out.println(e.getMessage());
        }
    }

Cara njaluk njupuk file server. Kaya sing wis kasebut ing bagean ing sisih klien program, supaya bisa nransfer file, sampeyan kudu ngerti ukurane, disimpen ing integer sing dawa, mula aku dibagi dadi array 4 bait, nransfer bait-byte. menyang soket, banjur, sawise nampa lan nglumpuk ing klien menyang nomer bali, Aku nransfer kabeh bait sing nggawe file, maca saka stream input saka file.


 private  void get(String source, String dest){
        File sending = new File(source);
        try {
            FileInputStream readFromFile = new FileInputStream(sending);
            byte[] arr = readFromFile.readAllBytes();
            byte[] bytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(sending.length()).array();
            for (int i = 0; i<Long.SIZE / Byte.SIZE; i++)
                sout.write(bytes[i]);
            sout.flush();
            for (byte b : arr)
                sout.write(b);
        }
        catch (Exception e){
            System.out.println(e.getMessage());
        }
    };

Cara getAndParseInput padha karo klien, mung bedane yaiku maca data saka soket tinimbang saka keyboard. Kode kasebut ana ing repositori, kaya pamilih.
Ing kasus iki, initialization diselehake ing blok kapisah saka kode, amarga ing implementasine iki, sawise transfer rampung, sumber daya dirilis lan reoccupied maneh - maneh kanggo nyedhiyani pangayoman marang bocor memori.

    private void  incialization()
    {
        try {
            serverSocket = new ServerSocket(port);
            socket = serverSocket.accept();
            sin = socket.getInputStream();
            sout = socket.getOutputStream();
        }
        catch (Exception e) {
            System.out.print(e.getMessage());
        }
    }

Kanggo ngringkes:

Kita wis nulis variasi kita dhewe ing protokol transfer data sing prasaja lan nemtokake cara kerjane. Ing asas, aku ora nemokake Amerika ing kene lan ora nulis akeh perkara anyar, nanging ora ana artikel sing padha babagan HabrΓ©, lan minangka bagΓ©an saka nulis seri artikel babagan keperluan cmd, ora bisa didemek.

Cathetan:

Repositori kode sumber
Sedhela babagan TFTP
Ing bab sing padha, nanging ing Rusia

Source: www.habr.com

Tuku hosting sing dipercaya kanggo situs kanthi proteksi DDoS, server VPS VDS πŸ”₯ Tuku hosting situs web sing bisa dipercaya nganggo proteksi DDoS, server VPS VDS | ProHoster