Manoratra rindrambaiko miaraka amin'ny fampiasa Windows client-server utility, part 02

Manohy ny andian-dahatsoratra mitohy natokana ho an'ny fampiharana manokana ny fampitaovana fampiononana Windows, tsy afaka ny tsy hiresaka momba ny TFTP (Trivial File Transfer Protocol) - protocole famindrana rakitra tsotra.

Toy ny tamin'ny fotoana farany, andeha hojerentsika fohifohy ny teoria, jereo ny code izay mampihatra fiasa mitovy amin'ilay ilaina, ary diniho izany. Ny antsipiriany bebe kokoa - eo ambanin'ny fanapahana

Tsy handika ny fampahalalana momba ny fanondroana aho, rohy izay hita amin'ny fomba nentim-paharazana amin'ny faran'ny lahatsoratra, holazaiko fotsiny fa amin'ny fotony, ny TFTP dia fiovaovana tsotra amin'ny protocol FTP, izay misy ny rafitra fanaraha-maso ny fidirana. nesorina, ary raha ny marina dia tsy misy na inona na inona eto afa-tsy ny baiko amin'ny fandraisana sy famindrana rakitra. Na izany aza, mba hahatonga ny fampiharana ataontsika ho kanto kokoa sy hifanaraka amin'ny fitsipika ankehitriny amin'ny fanoratana kaody, ny syntax dia niova kely - tsy manova ny fitsipiky ny asa izany, fa ny interface, IMHO, dia lasa lojika kokoa ary dia manambatra ny lafiny tsara amin'ny FTP sy TFTP.

Indrindra indrindra, rehefa natomboka ny mpanjifa dia mangataka ny adiresy IP an'ny mpizara sy ny seranan-tsambo izay misokatra ny TFTP mahazatra (noho ny tsy fifanarahana amin'ny protocole mahazatra, dia noheveriko fa mety ny mamela ny mpampiasa hisafidy seranana), ary avy eo a Ny fifandraisana dia mitranga, vokatr'izany ny mpanjifa dia afaka mandefa ny iray amin'ireo baiko - mahazo na mametraka, mandray na mandefa rakitra amin'ny mpizara. Ny rakitra rehetra dia alefa amin'ny fomba binary mba hanatsorana ny lojika.

Mba hampiharana ny protocol dia nampiasa kilasy 4 aho taloha:

  • TFTPClient
  • TFTPServer
  • TFTPClientTester
  • TFTPServerTester

Noho ny zava-misy fa ny kilasy fitsapana dia tsy misy afa-tsy amin'ny debugging ny lehibe indrindra, dia tsy hamakafaka azy ireo aho, fa ny code dia ho ao amin'ny tahiry; rohy mankany aminy dia hita any amin'ny faran'ny lahatsoratra. Ankehitriny dia hijery ireo kilasy lehibe aho.

TFTPClient

Ny asan'ity kilasy ity dia ny mampifandray amin'ny mpizara lavitra amin'ny alΓ lan'ny laharan'ny ip sy ny seranan-tsambo, mamaky baiko avy amin'ny stream input (amin'ity tranga ity, ny klavier), manadihady azy, mamindra izany amin'ny mpizara, ary miankina amin'ny hoe mila mandefa na mandray rakitra, mamindra na mahazo.

Toy izao ny kaody amin'ny fandefasana ny mpanjifa hifandray amin'ny mpizara ary miandry baiko avy amin'ny stream input. Maromaro ny fari-piainana maneran-tany izay ampiasaina eto dia nofaritana ivelan'ny lahatsoratra, ao amin'ny lahatsoratra feno amin'ny fandaharana. Noho ny maha-zava-dehibe azy ireo dia tsy mitanisa azy ireo aho mba tsy hamenoana ny lahatsoratra.

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

Andeha hojerentsika ireo fomba antsoina amin'ity andian-kaody ity:

Eto ny rakitra dia alefa - amin'ny fampiasana scanner, dia manolotra ny votoatin'ny rakitra ho toy ny array of bytes, izay soratanay tsirairay amin'ny socket, ary avy eo dia manidy azy izahay ary manokatra azy indray (tsy ny vahaolana mazava indrindra, fa miantoka ny famotsorana ireo loharano), ary avy eo dia mampiseho hafatra momba ny famindrana mahomby.

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

Ity sombin-kaody ity dia mamaritra ny famerenana ny angona avy amin'ny mpizara. Tsy misy dikany indray ny zava-drehetra, ny bloc code voalohany ihany no mahaliana. Mba hahatakarana tsara hoe firy bytes mila vakiana avy amin'ny socket dia mila mahafantatra ny lanjan'ny rakitra nafindra ianao. Ny haben'ny rakitra ao amin'ny server dia aseho ho integer lava, ka 4 bytes no ekena eto, izay avadika ho isa iray avy eo. Tsy fomba fiasa Java loatra izany, fa mitovy amin'ny SI, fa mamaha ny olana.

Dia tsinontsinona ny zava-drehetra - mahazo isa fantatra avy amin'ny socket isika ary manoratra azy ireo amin'ny rakitra iray, ary avy eo dia mampiseho hafatra mahomby.

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

Raha misy baiko hafa ankoatra ny mahazo na apetraka ao amin'ny varavarankelin'ny mpanjifa dia hantsoina ny asa showErrorMessage, izay manondro fa diso ny fampidirana. Noho ny zava-mahagaga dia tsy hanonona izany aho. Somary mahaliana kokoa ny fiasan'ny fandraisana sy fanaparitahana ny tady fampidirana. Ampitao ao anatiny ny scanner, izay antenainay fa hahazo tsipika misaraka amin'ny habaka roa ary misy ny baiko, ny adiresy loharano ary ny adiresiny.

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

Mandefa baikoβ€”mamindra ny baiko nampidirina avy amin'ny scanner mankany amin'ny socket ary manery azy halefa

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

Ny selector dia fiasa izay mamaritra ny hetsika ataon'ny programa miankina amin'ny tady nampidirina. Ny zava-drehetra eto dia tsy dia tsara loatra ary ny fika ampiasaina dia tsy ny tsara indrindra amin'ny fivoahana an-tery ivelan'ny sakana kaody, fa ny antony lehibe indrindra amin'izany dia ny tsy fisian'ny Java amin'ny zavatra sasany, toy ny solontena amin'ny C #, ny tondro fiasa avy amin'ny C ++, na amin'ny farafaharatsiny ny goto mahatsiravina sy mahatsiravina, izay ahafahanao mampihatra izany tsara tarehy. Raha fantatrao ny fomba hahatonga ny kaody ho kanto kokoa dia mandray ny fanakianana aho amin'ny fanehoan-kevitra. Amiko dia mila diksionera String-delegate eto fa tsy misy delege...

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

TFTPServer

Ny fiasan'ny mpizara dia tsy mitovy amin'ny asan'ny mpanjifa, amin'ny ankapobeny, fa ny baiko dia tsy avy amin'ny klavier, fa avy amin'ny socket. Ny fomba sasany dia mitovy amin'ny ankapobeny, ka tsy hotanisaiko fa ny fahasamihafana ihany no hokasihiko.

Hanombohana dia ampiasaina ny fomba fampandehanana, izay mandray seranan-tsambo ho fampidirana ary manodina ny angona fidirana avy amin'ny socket amin'ny loop mandrakizay.

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

Ny fomba put, izay mandrakotra ny fomba writeToFileFromSocket izay manokatra stream manoratra amin'ny rakitra iray ary manoratra ny byte fampidirana rehetra avy amin'ny socket, dia mampiseho hafatra milaza ny fahavitan'ny fifindrana rehefa vita ny fanoratana.

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

Ny fomba get dia mamerina ny rakitra mpizara. Araka ny efa voalaza ao amin'ny fizarana eo amin'ny lafiny mpanjifa amin'ny programa, mba hamindra amim-pahombiazana ny rakitra iray dia mila mahafantatra ny habeny ianao, voatahiry ao anaty integer lava, noho izany dia nozaraiko ho andiana 4 byte izy ireo, hamindra azy ireo byte-by-byte. mankany amin'ny socket, ary avy eo, rehefa nahazo sy nanangona azy ireo tamin'ny mpanjifa ho lasa isa miverina aho, dia mamindra ny bytes rehetra mandrafitra ny rakitra, mamaky avy amin'ny stream input avy amin'ny rakitra.


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

Ny fomba getAndParseInput dia mitovy amin'ny mpanjifa, ny hany mahasamihafa azy dia ny mamaky angona avy amin'ny socket fa tsy avy amin'ny klavier. Ny kaody dia ao amin'ny tahiry, toy ny selector.
Amin'ity tranga ity, ny fanombohana dia apetraka amin'ny andian-kaody misaraka, satria ao anatin'io fampiharana io, rehefa vita ny famindrana, dia avoaka sy amboarina indray ny loharanon-karena - mba hanomezana fiarovana amin'ny fahatapahan'ny fahatsiarovana.

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

Raha fintinina:

Vao avy nanoratra ny fiovaovantsika manokana tamin'ny protocole famindrana angon-drakitra tsotra izahay ary nahafantatra ny fomba tokony hiasana. Amin'ny ankapobeny, tsy nahita an'i Amerika aho teto ary tsy nanoratra zava-baovao betsaka, saingy tsy nisy lahatsoratra mitovy amin'izany tao amin'ny HabrΓ©, ary amin'ny ampahany amin'ny fanoratana lahatsoratra maromaro momba ny fampitaovana cmd dia tsy azo atao ny tsy hikasika izany.

andinin-tsoratra masina:

Repository loharanon-kaody
Fohy momba ny TFTP
Toy izany koa, fa amin'ny teny Rosiana

Source: www.habr.com

Add a comment