Kitba ta 'softwer bil-funzjonalità tal-utilitajiet Windows client-server, parti 02

Inkomplu s-serje kontinwa ta 'artikoli ddedikati għall-implimentazzjonijiet tad-dwana tal-utilitajiet tal-console tal-Windows, ma nistgħux ma nmissux ma' TFTP (Trivial File Transfer Protocol) - protokoll sempliċi ta' trasferiment ta 'fajls.

Bħala l-aħħar darba, ejja ngħaddu fil-qosor fuq it-teorija, ara l-kodiċi li timplimenta funzjonalità simili għal dik meħtieġa, u tanalizzah. Aktar dettalji - taħt il-qatgħa

Mhux se nikkopja-pejst informazzjoni ta 'referenza, links li tradizzjonalment jistgħu jinstabu fl-aħħar tal-artikolu, jien ser ngħid biss li fil-qalba tiegħu, TFTP hija varjazzjoni simplifikata tal-protokoll FTP, li fiha l-issettjar tal-kontroll tal-aċċess tneħħa, u fil-fatt m'hemm xejn hawn ħlief kmandi biex tirċievi u tittrasferixxi fajl . Madankollu, sabiex l-implimentazzjoni tagħna ssir ftit aktar eleganti u adattata għall-prinċipji attwali tal-kitba tal-kodiċi, is-sintassi nbidlet ftit - dan ma jbiddilx il-prinċipji tal-operat, iżda l-interface, IMHO, isir ftit aktar loġiku u jgħaqqad l-aspetti pożittivi ta 'FTP u TFTP.

B'mod partikolari, meta tniedi, il-klijent jitlob l-indirizz IP tas-server u l-port li fih ikun miftuħ it-TFTP tad-dwana (minħabba l-inkompatibilità mal-protokoll standard, qiest li kien xieraq li tħalli lill-utent il-ħila li jagħżel port), wara li a konnessjoni sseħħ, bħala riżultat li l-klijent jista 'jibgħat wieħed mill-kmandi - tikseb jew tpoġġi, li tirċievi jew tibgħat fajl lis-server. Il-fajls kollha jintbagħtu fil-modalità binarja biex tissimplifika l-loġika.

Biex nimplimenta l-protokoll, tradizzjonalment użajt 4 klassijiet:

  • TFTPClient
  • TFTPServer
  • TFTPClientTester
  • TFTPServerTester

Minħabba l-fatt li l-klassijiet tal-ittestjar jeżistu biss għad-debugging ta 'dawk ewlenin, mhux se janalizzahom, iżda l-kodiċi se jkun fir-repożitorju jista' jinstab link għalih fl-aħħar tal-artiklu; Issa se nħares lejn il-klassijiet ewlenin.

TFTPClient

Il-kompitu ta 'din il-klassi huwa li tikkonnettja ma' server remot billi tuża l-ip u n-numru tal-port tagħha, aqra kmand mill-fluss ta 'input (f'dan il-każ, it-tastiera), teżaminaha, tittrasferiha lis-server, u, skond jekk int jeħtieġ li tibgħat jew tirċievi fajl, tittrasferih jew tikseb.

Il-kodiċi għat-tnedija tal-klijent biex jgħaqqad mas-server u stenna għal kmand mill-fluss ta 'input jidher bħal dan. Numru ta 'varjabbli globali li huma użati hawn huma deskritti barra l-artikolu, fit-test sħiħ tal-programm. Minħabba t-trivjalità tagħhom, ma niċċitahomx biex ma jgħabbix żżejjed l-artiklu.

 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());
        }
    }

Ejja mmorru fuq il-metodi msejħa f'dan il-blokk ta 'kodiċi:

Hawnhekk il-fajl jintbagħat - bl-użu ta 'skaner, aħna nippreżentaw il-kontenut tal-fajl bħala firxa ta' bytes, li niktbu wieħed wieħed fis-sokit, u wara nagħlquh u niftħu mill-ġdid (mhux l-aktar soluzzjoni ovvja, iżda tiggarantixxi r-rilaxx tar-riżorsi), u wara aħna nuru messaġġ dwar trasferiment b'suċċess.

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());
        }
    }

Dan il-framment tal-kodiċi jiddeskrivi l-irkupru tad-dejta mis-server. Kollox huwa għal darb'oħra trivjali, l-ewwel blokk ta 'kodiċi biss huwa ta' interess. Sabiex tifhem eżattament kemm il-bytes jeħtieġ li jinqraw mis-sokit, trid tkun taf kemm jiżen il-fajl trasferit. Id-daqs tal-fajl fuq is-server huwa rappreżentat bħala numru sħiħ twil, għalhekk 4 bytes huma aċċettati hawnhekk, li sussegwentement jiġu kkonvertiti f'numru wieħed. Dan mhuwiex approċċ Java ħafna, huwa pjuttost simili għal SI, iżda jsolvi l-problema tiegħu.

Imbagħad kollox huwa trivjali - nirċievu numru magħruf ta 'bytes mis-sokit u niktbuhom f'fajl, u wara aħna nuru messaġġ ta' suċċess.

   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());
       }
    }

Jekk ġie mdaħħal kmand ieħor għajr get jew put fit-tieqa tal-klijent, tissejjaħ il-funzjoni showErrorMessage, li tindika li l-input ma kienx korrett. Minħabba t-trivjalità, mhux se niċċitaha. Kemmxejn aktar interessanti hija l-funzjoni li tirċievi u tinqasam is-sekwenza tad-dħul. Aħna ngħaddu l-iskaner fih, li minnu nistennew li nirċievu linja separata minn żewġ spazji u li jkun fiha l-kmand, l-indirizz tas-sors u l-indirizz tad-destinazzjoni.

    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");
        }
    }

Tibgħat kmand—jitrażmetti l-kmand imdaħħal mill-iskaner għas-socket u jġiegħel li jintbagħat

    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());
        }
    }

Selettur huwa funzjoni li tiddetermina l-azzjonijiet tal-programm skont is-sekwenza mdaħħla. Kollox hawnhekk mhuwiex sabiħ ħafna u t-trick użat mhuwiex l-aħjar wieħed b'ħruġ sfurzat barra l-blokk tal-kodiċi, iżda r-raġuni ewlenija għal dan hija n-nuqqas f'Java ta 'xi affarijiet, bħal delegati f'C#, indikaturi tal-funzjoni minn C++, jew f' inqas il-goto terribbli u terribbli, li jippermettu li timplimenta dan beautifully. Jekk taf kif tagħmel il-kodiċi ftit aktar eleganti, nilqa' l-kritika fil-kummenti. Jidhirli li hawnhekk hemm bżonn dizzjunarju String-delegat, iżda m'hemm l-ebda delegat...

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

TFTPServer

Il-funzjonalità tas-server hija differenti mill-funzjonalità tal-klijent, b'mod ġenerali, biss f'dak li kmandi jaslu għaliha mhux mit-tastiera, iżda mis-sokit. Uħud mill-metodi huma ġeneralment l-istess, għalhekk mhux se niċċitahom, se tmiss biss id-differenzi.

Biex tibda, jintuża l-metodu run, li jirċievi port bħala input u jipproċessa d-dejta tal-input mis-sokit f'linja eterna.

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

Il-metodu put, li jgeżwer il-metodu writeToFileFromSocket li jiftaħ fluss ta 'kitba għal fajl u jikteb il-bytes ta' input kollha mis-socket, juri messaġġ li jindika t-tlestija b'suċċess tat-trasferiment meta titlesta l-kitba.

    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());
        }
    }

Il-metodu get jirkupra l-fajl tas-server. Kif diġà ssemma fit-taqsima fuq in-naħa tal-klijent tal-programm, biex tittrasferixxi b'suċċess fajl għandek bżonn tkun taf id-daqs tiegħu, maħżun f'numru sħiħ twil, għalhekk qassejtha f'firxa ta '4 bytes, ittrasferihom byte b'byte għas-sokit, u mbagħad, wara li rċevejthom u assemblajthom fuq il-klijent f'numru lura, nittrasferixxi l-bytes kollha li jiffurmaw il-fajl, aqra mill-fluss ta 'input mill-fajl.


 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());
        }
    };

Il-metodu getAndParseInput huwa l-istess bħal fil-klijent, l-unika differenza hija li jaqra d-dejta mis-socket aktar milli mit-tastiera. Il-kodiċi jinsab fir-repożitorju, bħal selettur.
F'dan il-każ, l-inizjalizzazzjoni titqiegħed fi blokka separata ta 'kodiċi, għaliex fi ħdan din l-implimentazzjoni, wara li jitlesta t-trasferiment, ir-riżorsi jiġu rilaxxati u okkupati mill-ġdid - għal darb'oħra biex jipprovdu protezzjoni kontra tnixxijiet tal-memorja.

    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());
        }
    }

Biex tqassar:

Għadna kemm ktibna l-varjazzjoni tagħna stess fuq protokoll ta’ trasferiment tad-dejta sempliċi u sibna kif għandha taħdem. Fil-prinċipju, ma skoprejtx l-Amerika hawn u ma ktibtx ħafna affarijiet ġodda, iżda ma kienx hemm artikli simili fuq Habré, u bħala parti mill-kitba ta 'serje ta' artikli dwar l-utilitajiet cmd kien impossibbli li ma tmissx fuqha.

Referenzi:

Repożitorju tal-kodiċi tas-sors
Fil-qosor dwar TFTP
L-istess ħaġa, iżda bir-Russu

Sors: www.habr.com

Żid kumment