ونڊوز ڪلائنٽ-سرور يوٽيلٽيز جي ڪارڪردگي سان سافٽ ويئر لکڻ، حصو 02

ونڊوز ڪنسول يوٽيلٽيز جي حسب ضرورت لاڳو ڪرڻ لاءِ وقف ڪيل آرٽيڪلز جي جاري سيريز کي جاري رکندي، اسان TFTP (Trivial File Transfer Protocol) - هڪ سادي فائل ٽرانسفر پروٽوڪول تي رابطو ڪرڻ کانسواءِ مدد نٿا ڪري سگهون.

جيئن ته آخري ڀيرو، اچو ته مختصر طور تي نظريي تي وڃو، ڪوڊ ڏسو جيڪو گهربل ڪارڪردگي سان ملندڙ ڪارڪردگي کي لاڳو ڪري ٿو، ۽ ان جو تجزيو ڪيو. وڌيڪ تفصيل - کٽ هيٺ

مان ڪاپي پيسٽ نه ڪندس ريفرنس جي معلومات، لنڪس جيڪي روايتي طور تي آرٽيڪل جي آخر ۾ ڳولي سگهجن ٿيون، مان صرف ايترو چوندس ته ان جي بنيادي طور تي، TFTP FTP پروٽوڪول جي هڪ آسان تبديلي آهي، جنهن ۾ رسائي ڪنٽرول سيٽنگ آهي. هٽايو ويو آهي، ۽ حقيقت ۾ هتي ڪجھ به نه آهي سواء هڪ فائل حاصل ڪرڻ ۽ منتقل ڪرڻ لاء حڪمن جي. تنهن هوندي، اسان جي عمل کي ٿورو وڌيڪ خوبصورت ۽ لکڻ جي ڪوڊ جي موجوده اصولن سان ٺهڪندڙ بڻائڻ لاء، نحو کي ٿورو تبديل ڪيو ويو آهي - اهو عمل جي اصولن کي تبديل نٿو ڪري، پر انٽرفيس، IMHO، ٿورو وڌيڪ منطقي ٿي وڃي ٿو ۽ FTP ۽ TFTP جي مثبت پهلوئن کي گڏ ڪري ٿو.

خاص طور تي، جڏهن لانچ ڪيو ويو آهي، ڪلائنٽ سرور جي IP پتي ۽ بندرگاهن جي درخواست ڪري ٿو جنهن تي ڪسٽم TFTP کليل آهي (معياري پروٽوڪول سان مطابقت نه هجڻ جي ڪري، مون ان کي مناسب سمجهيو ته صارف کي بندرگاهه چونڊڻ جي صلاحيت ڇڏي ڏيو)، جنهن کان پوء ڪنيڪشن ٿيندي آهي، جنهن جي نتيجي ۾ ڪلائنٽ موڪلي سگهي ٿو هڪ حڪم - حاصل ڪريو يا رکو، حاصل ڪرڻ يا سرور ڏانهن فائل موڪلڻ لاء. سڀني فائلن کي بائنري موڊ ۾ موڪليو ويو آهي منطق کي آسان ڪرڻ لاء.

پروٽوڪول کي لاڳو ڪرڻ لاء، مون روايتي طور تي 4 طبقن کي استعمال ڪيو:

  • TFTPC ڪلائنٽ
  • TFTPS سرور
  • TFTPC ڪلائنٽ ٽيسٽ
  • TFTPSserverTester

انهي حقيقت جي ڪري ته ٽيسٽنگ ڪلاس صرف بنيادي ماڻهن کي ڊيبگ ڪرڻ لاءِ موجود آهن، مان انهن جو تجزيو نه ڪندس، پر ڪوڊ مخزن ۾ هوندو؛ ان جي لنڪ آرٽيڪل جي آخر ۾ ملي سگهي ٿي. هاڻي مان مکيه طبقن کي ڏسندس.

TFTPC ڪلائنٽ

هن ڪلاس جو ڪم هڪ ريموٽ سرور سان ان جي ip ۽ پورٽ نمبر ذريعي ڳنڍڻ آهي، ان پٽ اسٽريم مان هڪ ڪمانڊ پڙهو (هن صورت ۾، ڪي بورڊ)، ان کي پارس ڪرڻ، ان کي سرور ڏانهن منتقل ڪرڻ، ۽ ان تي منحصر آهي ته ڇا توهان فائل موڪلڻ يا وصول ڪرڻ، ان کي منتقل ڪرڻ يا حاصل ڪرڻ جي ضرورت آهي.

سرور سان ڳنڍڻ لاءِ ڪلائنٽ شروع ڪرڻ جو ڪوڊ ۽ ان پٽ اسٽريم مان حڪم جو انتظار ڪرڻ هن طرح نظر اچي ٿو. ڪيترائي عالمي متغير جيڪي هتي استعمال ڪيا ويا آهن مضمون کان ٻاهر بيان ڪيا ويا آهن، پروگرام جي مڪمل متن ۾. انهن جي بيوقوفيءَ جي ڪري، مان انهن جو حوالو نه ٿو ڏيان ته جيئن مضمون اوورلوڊ نه ٿئي.

 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++ مان فنڪشن پوائنٽر، يا گهٽ ۾ گهٽ خوفناڪ ۽ خوفناڪ گوتو، جيڪو توهان کي هن سهڻي طريقي سان لاڳو ڪرڻ جي اجازت ڏئي ٿو. جيڪڏهن توهان ڄاڻو ٿا ته ڪوڊ کي ٿورو وڌيڪ خوبصورت ڪيئن ٺاهيو، آئون تبصرن ۾ تنقيد کي ڀليڪار ڪريان ٿو. مون کي لڳي ٿو ته هتي هڪ String-delegate ڊڪشنري جي ضرورت آهي، پر هتي ڪو به نمائندو ناهي...

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

پوٽ جو طريقو، جيڪو Wraps 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());
        }
    }

اختصار ڪرڻ:

اسان صرف هڪ سادي ڊيٽا جي منتقلي پروٽوڪول تي اسان جي پنهنجي تبديلي کي لکيو آهي ۽ اهو معلوم ڪيو ته اهو ڪيئن ڪم ڪرڻ گهرجي. اصولي طور تي، مون هتي آمريڪا کي دريافت نه ڪيو آهي ۽ نه گهڻو ڪجهه نيون شيون لکيون آهن، پر Habré تي اهڙا مضمون نه هئا، ۽ cmd افاديت بابت آرٽيڪل لکڻ جي هڪ حصي جي طور تي اهو ناممڪن هو ته ان تي هٿ نه رکي.

حوالا:

ماخذ ڪوڊ مخزن
TFTP بابت مختصر طور
ساڳي شيء، پر روسي ۾

جو ذريعو: www.habr.com

تبصرو شامل ڪريو