වින්ඩෝස් සේවාදායක-සේවාදායක උපයෝගිතා වල ක්‍රියාකාරීත්වය සහිත ලිවීමේ මෘදුකාංග, 02 කොටස

වින්ඩෝස් කොන්සෝල උපයෝගිතා අභිරුචි ක්‍රියාත්මක කිරීම සඳහා කැප කර ඇති ලිපි මාලාව දිගටම කරගෙන යමින්, අපට TFTP (Trivial File Transfer Protocol) - සරල ගොනු හුවමාරු ප්‍රොටෝකෝලය ස්පර්ශ කිරීම වැළැක්විය නොහැක.

පසුගිය වතාවේ මෙන්, අපි කෙටියෙන් න්‍යාය හරහා යමු, අවශ්‍ය ක්‍රියාකාරිත්වයට සමාන ක්‍රියාකාරීත්වය ක්‍රියාත්මක කරන කේතය බලන්න සහ එය විශ්ලේෂණය කරමු. වැඩි විස්තර - කප්පාදුව යටතේ

ලිපියේ අවසානයේ සාම්ප්‍රදායිකව සොයාගත හැකි යොමු තොරතුරු මම පිටපත් නොකරමි, TFTP යනු ප්‍රවේශ පාලන සැකසුම වන FTP ප්‍රොටෝකෝලයේ සරල කළ ප්‍රභේදයක් බව මම කියමි. ඉවත් කර ඇත, සහ ඇත්ත වශයෙන්ම මෙහි ගොනුවක් ලබා ගැනීම සහ මාරු කිරීම සඳහා විධාන හැර වෙනත් කිසිවක් නොමැත . කෙසේ වෙතත්, අපගේ ක්‍රියාත්මක කිරීම තව ටිකක් අලංකාර කිරීමට සහ ලිවීමේ කේතයේ වර්තමාන මූලධර්මවලට අනුවර්තනය වීමට, වාක්‍ය ඛණ්ඩය තරමක් වෙනස් කර ඇත - මෙය ක්‍රියාකාරීත්වයේ මූලධර්ම වෙනස් නොකරයි, නමුත් අතුරු මුහුණත, IMHO, ටිකක් තාර්කික වේ. FTP සහ TFTP හි ධනාත්මක අංශ ඒකාබද්ධ කරයි.

විශේෂයෙන්, දියත් කරන විට, සේවාදායකයා සේවාදායකයේ IP ලිපිනය සහ අභිරුචි TFTP විවෘත කර ඇති වරාය ඉල්ලා සිටී (සම්මත ප්‍රොටෝකෝලය සමඟ නොගැලපීම හේතුවෙන්, පරිශීලකයාට වරායක් තෝරා ගැනීමේ හැකියාව ලබා දීම සුදුසු යැයි මම සැලකුවෙමි), ඉන් පසුව සම්බන්ධතාවය ඇතිවේ, එහි ප්‍රති result ලයක් ලෙස සේවාදායකයාට එක් විධානයක් යැවිය හැකිය - ලබා ගැනීම හෝ තැබීම, ගොනුවක් ලබා ගැනීමට හෝ සේවාදායකයට යැවීමට. තර්කය සරල කිරීම සඳහා සියලුම ගොනු ද්විමය ආකාරයෙන් යවනු ලැබේ.

ප්රොටෝකෝලය ක්රියාත්මක කිරීම සඳහා, මම සාම්ප්රදායිකව පන්ති 4 ක් භාවිතා කළෙමි:

  • TFTPClient
  • TFTPS සේවාදායකය
  • TFTPClientTester
  • TFTPSserverTester

පරීක්ෂණ පන්ති පවතින්නේ ප්‍රධාන ඒවා නිදොස් කිරීම සඳහා පමණක් වන බැවින්, මම ඒවා විශ්ලේෂණය නොකරමි, නමුත් කේතය ගබඩාවේ ඇත, එයට සබැඳියක් ලිපියේ අවසානයේ සොයාගත හැකිය. දැන් මම ප්රධාන පන්ති බලන්නම්.

TFTPClient

මෙම පන්තියේ කාර්යය වන්නේ එහි ip සහ port අංකය භාවිතා කර දුරස්ථ සේවාදායකයකට සම්බන්ධ වීම, ආදාන ප්‍රවාහයෙන් විධානයක් කියවීම (මෙම අවස්ථාවේදී, යතුරුපුවරුව), එය විග්‍රහ කිරීම, එය සේවාදායකයට මාරු කිරීම සහ ඔබ මත පදනම්ව ගොනුවක් යැවීමට හෝ ලැබීමට, එය මාරු කිරීමට හෝ ලබා ගැනීමට අවශ්‍ය වේ.

සේවාදායකයට සම්බන්ධ වීමට සහ ආදාන ප්‍රවාහයෙන් විධානයක් එනතෙක් රැඳී සිටීමට සේවාදායකයා දියත් කිරීමේ කේතය මේ ආකාරයෙන් පෙනේ. මෙහි භාවිතා වන ගෝලීය විචල්‍යයන් ගණනාවක් ලිපියෙන් පිටත, වැඩසටහනේ සම්පූර්ණ පෙළෙහි විස්තර කර ඇත. ඒවායේ ඇති නොවැදගත්කම නිසා, ලිපිය අධික ලෙස පැටවීම නොකිරීමට මම ඒවා උපුටා නොගනිමි.

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

අපි මෙම කේත කොටසේ ඇති ක්‍රම හරහා යමු:

මෙන්න ගොනුව යවනු ලැබේ - ස්කෑනරයක් භාවිතා කරමින්, අපි ගොනුවේ අන්තර්ගතය බයිට් මාලාවක් ලෙස ඉදිරිපත් කරමු, එය අපි සොකට් එකට එකින් එක ලියන්නෙමු, ඉන්පසු අපි එය වසා නැවත විවෘත කරන්නෙමු (වඩාත් පැහැදිලි විසඳුම නොවේ, නමුත් එය සම්පත් මුදා හැරීම සහතික කරයි), ඉන්පසු අපි සාර්ථක හුවමාරුව පිළිබඳ පණිවිඩයක් පෙන්වමු.

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

මෙම කේත කොටස සේවාදායකයෙන් දත්ත ලබා ගැනීම විස්තර කරයි. සෑම දෙයක්ම නැවතත් සුළුපටු ය, පළමු කේතය පමණක් උනන්දුවක් දක්වයි. සොකට් එකෙන් කොපමණ බයිට් කියවිය යුතුද යන්න හරියටම තේරුම් ගැනීම සඳහා, මාරු කළ ගොනුවේ බර කොපමණ දැයි ඔබ දැනගත යුතුය. සේවාදායකයේ ගොනු ප්‍රමාණය දිගු පූර්ණ සංඛ්‍යාවක් ලෙස නිරූපණය කෙරේ, එබැවින් මෙහි බයිට් 4 ක් පිළිගනු ලැබේ, ඒවා පසුව එක් අංකයක් බවට පරිවර්තනය වේ. මෙය ඉතා ජාවා ප්‍රවේශයක් නොවේ, එය SI සඳහා තරමක් සමාන ය, නමුත් එය එහි ගැටළුව විසඳයි.

එවිට සෑම දෙයක්ම සුළුපටු නොවේ - අපට සොකට් එකෙන් දන්නා බයිට් සංඛ්‍යාවක් ලැබෙන අතර ඒවා ගොනුවකට ලියන්න, ඉන්පසු අපි සාර්ථක පණිවිඩයක් පෙන්වමු.

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

ලබා ගැනීම හෝ දැමීම හැර වෙනත් විධානයක් සේවාදායක කවුළුව තුළට ඇතුළු කර ඇත්නම්, ආදානය වැරදි බව පෙන්නුම් කරමින් showErrorMessage ශ්‍රිතය කැඳවනු ලැබේ. සුළු දෙයක් නිසා, මම එය උපුටා දක්වන්නේ නැහැ. ආදාන තන්තුව ලැබීමේ සහ බෙදීමේ කාර්යය තරමක් සිත්ගන්නා සුළුය. අපි ස්කෑනරය එයට යවන්නෙමු, එයින් අපි හිස් දෙකකින් වෙන් කරන ලද සහ විධානය, මූලාශ්‍ර ලිපිනය සහ ගමනාන්ත ලිපිනය අඩංගු රේඛාවක් ලැබීමට බලාපොරොත්තු වෙමු.

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

විධානයක් යැවීම - ස්කෑනරයෙන් ඇතුල් කරන ලද විධානය සොකට් වෙත සම්ප්රේෂණය කර එය යැවීමට බල කරයි

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

තේරීම් කාරකය යනු ඇතුළත් කළ තන්තුව මත පදනම්ව වැඩසටහනේ ක්‍රියා තීරණය කරන ශ්‍රිතයකි. මෙහි ඇති සෑම දෙයක්ම ඉතා අලංකාර නොවන අතර භාවිතා කරන උපක්‍රමය කේත බ්ලොක් එකෙන් පිටත බලහත්කාරයෙන් පිටවීම සමඟ හොඳම එක නොවේ, නමුත් මෙයට ප්‍රධාන හේතුව වන්නේ C# හි නියෝජිතයින්, C++ වෙතින් ක්‍රියාකාරී දර්ශක වැනි සමහර දේවල් Java හි නොමැති වීමයි. අවම වශයෙන් භයානක හා භයානක ගෝටෝ, මෙය අලංකාර ලෙස ක්‍රියාත්මක කිරීමට ඔබට ඉඩ සලසයි. කේතය තව ටිකක් අලංකාර කරන්නේ කෙසේදැයි ඔබ දන්නේ නම්, අදහස් දැක්වීමේදී මම විවේචන සාදරයෙන් පිළිගනිමි. මට පේන විදියට මෙහි String-deligate ශබ්දකෝෂයක් අවශ්‍යයි, නමුත් නියෝජිතයෙක් නැහැ...

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

TFTPS සේවාදායකය

සේවාදායකයේ ක්‍රියාකාරිත්වය සේවාදායකයාගේ ක්‍රියාකාරිත්වයට වඩා වෙනස් වේ, විශාල වශයෙන්, විධානයන් එයට පැමිණෙන්නේ යතුරුපුවරුවෙන් නොව සොකට් එකෙන් පමණි. සමහර ක්‍රම සාමාන්‍යයෙන් සමාන වේ, එබැවින් මම ඒවා උපුටා දක්වන්නේ නැත, මම වෙනස්කම් පමණක් ස්පර්ශ කරමි.

ආරම්භ කිරීම සඳහා, ධාවන ක්‍රමය භාවිතා කරනු ලැබේ, එය ආදානය ලෙස වරායක් ලබා ගන්නා අතර සොකට් එකෙන් ආදාන දත්ත සදාකාලික ලූපයකින් සකසයි.

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

ගොනුවකට ලිවීමේ ප්‍රවාහයක් විවෘත කරන සහ සොකට් එකෙන් සියලුම ආදාන බයිට් ලියන writeToFileFromSocket ක්‍රමය ඔතා, ලිවීම අවසන් වූ විට මාරු කිරීම සාර්ථකව නිම කළ බවට පණිවිඩයක් පෙන්වයි.

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

ලබා ගැනීමේ ක්‍රමය සේවාදායක ගොනුව ලබා ගනී. වැඩසටහනේ සේවාදායක පැත්තේ කොටසේ දැනටමත් සඳහන් කර ඇති පරිදි, ගොනුවක් සාර්ථකව මාරු කිරීම සඳහා එහි විශාලත්වය දැන ගැනීමට අවශ්‍ය වේ, දිගු පූර්ණ සංඛ්‍යාවක ගබඩා කර ඇත, එබැවින් මම එය බයිට් 4 ක අරාවකට බෙදා ඒවා බයිට්-බයිට් වෙත මාරු කරමි. සොකට් එකට, පසුව, ඒවා ග්‍රාහකයා මත නැවත අංකයකට ලබාගෙන එකලස් කිරීමෙන් පසු, මම ගොනුව සෑදෙන සියලුම බයිට් මාරු කරමි, ගොනුවෙන් ආදාන ප්‍රවාහයෙන් කියවා ඇත.


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

getAndParseInput ක්‍රමය සේවාලාභියා තුළ ඇති ආකාරයටම වේ, එකම වෙනස වන්නේ එය යතුරු පුවරුවෙන් නොව සොකට් එකෙන් දත්ත කියවීමයි. තේරීම්කාරකය මෙන් කේතය ගබඩාවේ ඇත.
මෙම අවස්ථාවෙහිදී, ආරම්භ කිරීම වෙනම කේතයක් තුළ තබා ඇත, මන්ද මෙම ක්‍රියාත්මක කිරීම තුළ, මාරු කිරීම අවසන් වූ පසු, සම්පත් මුදා හරිනු ලබන අතර නැවත නැවත අත්පත් කර ගනු ලැබේ - නැවත මතක කාන්දුවීම් වලින් ආරක්ෂාව සැපයීම සඳහා.

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

සාරාංශ ගත කිරීමට:

අපි සරල දත්ත හුවමාරු ප්‍රොටෝකෝලයක අපගේම විචලනය ලියා එය ක්‍රියා කළ යුතු ආකාරය සොයා ගෙන ඇත. ප්‍රතිපත්තිමය වශයෙන්, මම මෙහි ඇමරිකාව සොයා නොගත් අතර බොහෝ අලුත් දේවල් ලියා නැත, නමුත් හබ්‍රේ පිළිබඳ සමාන ලිපි කිසිවක් නොතිබූ අතර, cmd උපයෝගිතා පිළිබඳ ලිපි මාලාවක් ලිවීමේ කොටසක් ලෙස එය ස්පර්ශ නොකිරීමට නොහැකි විය.

ආශ්රිත:

මූලාශ්ර කේත ගබඩාව
TFTP ගැන කෙටියෙන්
එකම දේ, නමුත් රුසියානු භාෂාවෙන්

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න