Ekri lojisyèl ak fonksyonalite Windows kliyan-sèvè sèvis piblik, pati 02

Kontinye seri atik kontinyèl yo konsakre nan aplikasyon koutim nan sèvis piblik konsole Windows, nou pa ka ede men manyen sou TFTP (Trivial File Transfer Protocol) - yon pwotokòl transfè dosye senp.

Kòm dènye fwa, ann ale yon ti tan sou teyori a, wè kòd ki aplike fonksyonalite ki sanble ak youn ki nesesè a, epi analize li. Plis detay - anba koupe a

Mwen pa pral kopye-kole enfòmasyon referans, lyen ki tradisyonèlman ka jwenn nan fen atik la, mwen pral sèlman di ke nan nwayo li yo, TFTP se yon varyasyon senplifye nan pwotokòl la FTP, nan ki anviwònman an kontwòl aksè gen. yo te retire, e an reyalite pa gen anyen isit la eksepte kòmandman pou resevwa ak transfere yon dosye . Sepandan, yo nan lòd yo fè aplikasyon nou an yon ti kras pi elegant ak adapte ak prensip aktyèl yo nan ekri kòd, sentaks la te yon ti kras chanje - sa a pa chanje prensip yo nan operasyon, men koòdone a, IMHO, vin yon ti kras pi lojik ak konbine aspè pozitif FTP ak TFTP.

An patikilye, lè yo te lanse, kliyan an mande adrès IP sèvè a ak pò a sou ki koutim TFTP louvri (akòz enkonpatibilite ak pwotokòl la estanda, mwen konsidere li apwopriye yo kite itilizatè a kapasite nan chwazi yon pò), apre sa yon koneksyon rive, kòm yon rezilta nan ki kliyan an ka voye youn nan kòmandman yo - jwenn oswa mete, resevwa oswa voye yon dosye nan sèvè a. Tout fichye yo voye nan mòd binè senplifye lojik la.

Pou aplike pwotokòl la, mwen tradisyonèlman itilize 4 klas:

  • TFTPClient
  • TFTPServer
  • TFTPClientTester
  • TFTPServerTester

Akòz lefèt ke klas tès yo egziste sèlman pou debogaj prensipal yo, mwen pa pral analize yo, men kòd la pral nan repozitwa a ka jwenn yon lyen nan fen atik la. Koulye a, mwen pral gade nan klas prensipal yo.

TFTPClient

Travay la nan klas sa a se konekte ak yon sèvè aleka lè l sèvi avèk nimewo IP ak pò li yo, li yon kòmandman ki soti nan kouran an opinyon (nan ka sa a, klavye a), analize li, transfere li nan sèvè a, epi, tou depann de si wi ou non ou. bezwen voye oswa resevwa yon dosye, transfere li oswa jwenn.

Kòd pou lanse kliyan an konekte ak sèvè a epi tann yon kòmandman nan kouran an opinyon sanble sa a. Yon kantite varyab mondyal ki itilize isit la yo dekri deyò atik la, nan tèks la konplè nan pwogram nan. Akoz trivialité yo, mwen pa site yo pou pa twò chaje atik la.

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

Ann ale sou metòd yo rele nan blòk kòd sa a:

Isit la yo voye dosye a - lè l sèvi avèk yon eskanè, nou prezante sa ki nan dosye a kòm yon etalaj de bytes, ke nou ekri youn pa youn nan priz la, apre sa nou fèmen li epi louvri li ankò (pa solisyon ki pi evidan, men li garanti liberasyon resous), apre sa nou montre yon mesaj sou transfè siksè.

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

Fragman kòd sa a dekri rekipere done ki soti nan sèvè a. Tout bagay ankò trivial, se sèlman premye blòk kòd la ki enterese. Yo nan lòd yo konprann egzakteman konbyen bytes yo dwe li nan priz la, ou bezwen konnen konbyen lajan fichye a transfere peze. Gwosè fichye a sou sèvè a reprezante kòm yon nonb antye long, kidonk 4 byte yo aksepte isit la, ki imedyatman konvèti nan yon nimewo. Sa a se pa yon apwòch trè Java, li se pito menm jan an pou SI, men li rezoud pwoblèm li yo.

Lè sa a, tout bagay se trivial - nou resevwa yon nimewo li te ye nan byte soti nan priz la epi ekri yo nan yon dosye, apre sa nou montre yon mesaj siksè.

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

Si yon lòt lòd pase jwenn oswa mete yo te antre nan fenèt kliyan an, yo pral rele fonksyon showErrorMessage, ki endike ke opinyon an pa kòrèk. Akòz triviality, mwen pa pral site li. Yon ti jan pi enteresan se fonksyon an nan resevwa ak divize fisèl la opinyon. Nou pase eskanè a nan li, ki soti nan ki nou espere resevwa yon liy separe pa de espas epi ki gen lòd la, adrès sous ak adrès destinasyon an.

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

Voye yon kòmand-transmèt kòmandman an te antre nan eskanè a nan priz la epi fòse li yo dwe voye

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

Yon seleksyon se yon fonksyon ki detèmine aksyon pwogram nan depann sou fisèl la antre. Tout bagay isit la se pa bèl anpil ak Trick yo itilize a se pa youn nan pi bon ak fòse sòti deyò blòk kòd la, men rezon prensipal pou sa a se absans nan Java nan kèk bagay, tankou delege nan C #, endikasyon fonksyon soti nan C++, oswa nan. pi piti goto a terib ak terib, ki pèmèt ou aplike sa a trè byen. Si ou konnen ki jan fè kòd la yon ti kras pi elegant, mwen akeyi kritik nan kòmantè yo. Mwen sanble ke yon diksyonè String-delege nesesè isit la, men pa gen okenn 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

Fonksyonalite nan sèvè a diferan de fonksyonalite kliyan an, an jeneral, sèlman nan ke kòmandman yo vini nan li pa soti nan klavye a, men soti nan priz la. Gen kèk nan metòd yo jeneralman menm, kidonk mwen pa pral ba yo, mwen pral sèlman manyen sou diferans ki genyen.

Pou kòmanse, yo itilize metòd la kouri, ki resevwa yon pò kòm opinyon ak trete done yo opinyon ki soti nan priz la nan yon bouk p'ap janm fini an.

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

Metòd mete a, ki vlope metòd writeToFileFromSocket ki ouvri yon kouran ekri nan yon fichye epi ekri tout bytes D 'soti nan priz la, montre yon mesaj ki endike transfè a konplete avèk siksè lè ekri a fini.

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

Metòd get la rekipere fichye sèvè a. Kòm deja mansyone nan seksyon an sou bò kliyan nan pwogram nan, avèk siksè transfere yon fichye ou bezwen konnen gwosè li yo, ki estoke nan yon nonb antye relatif long, Se konsa, mwen divize l 'nan yon etalaj de 4 octets, transfere yo byte-pa-byte. nan priz la, ak Lè sa a, te resevwa ak reyini yo sou kliyan an nan yon nimewo tounen, mwen transfere tout bytes yo ki fè moute fichye a, li soti nan kouran an opinyon nan dosye a.


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

Metòd getAndParseInput la se menm jan ak nan kliyan an, diferans lan sèlman se ke li li done ki soti nan priz la olye ke soti nan klavye a. Kòd la nan depo a, menm jan ak seleksyon an.
Nan ka sa a, inisyalizasyon an mete nan yon blòk separe nan kòd, paske nan aplikasyon sa a, apre transfè a fini, resous yo lage epi yo reokipe ankò - ankò pou bay pwoteksyon kont fwit memwa.

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

Pou rezime:

Nou jis ekri pwòp varyasyon nou sou yon pwotokòl transfè done ki senp epi nou kalkile kijan li ta dwe travay. Nan prensip, mwen pa t dekouvri Amerik isit la epi mwen pa t ekri anpil bagay nouvo, men pa t gen okenn atik ki sanble sou Habré, epi nan kad ekri yon seri atik sou sèvis piblik cmd li te enposib pa manyen sou li.

Lyen:

Depo kòd sous
Yon ti tan sou TFTP
Menm bagay la, men nan Ris

Sous: www.habr.com

Add nouvo kòmantè