سؤال

انا اعرف ماذا dup / dup2 يفعل، ولكن ليس لدي أي فكرة متى سيتم استخدامه.

أي أمثلة عملية؟

شكرا.

هل كانت مفيدة؟

المحلول

أحد الأمثلة على ذلك سيكون إعادة توجيه I / O. بالنسبة لهذا أنت شوكة عملية للطفل وإغلاق واصفات الملف Stdin أو Stdout الملفات (0 و 1)، ثم تقوم بعمل DUP () على Filedescriptor آخر من اختيارك والتي سيتم الآن تعيينها إلى أدنى واصف الملفات المتاحة، وهو في هذا حالة 0 أو 1.

باستخدام هذا يمكنك الآن تنفيذ أي عملية تابعة لأي عملية تابعة لها والتي ربما تكون غير مدركة لتطبيقك وعندما يكتب الطفل على Stdout (أو يقرأ من StDin، كل ما قمت بتكوينه) يتم كتابة البيانات على Filedescriptor المقدمة بدلا من ذلك.

قذائف تستخدم هذا لتنفيذ الأوامر مع الأنابيب، على سبيل المثال /bin/ls | more من خلال توصيل Stdout لعملية واحدة إلى Stdin من الآخر.

نصائح أخرى

أفضل سيناريو لفهم DUP و Dup2 هو إعادة التوجيه.
أول شيء نحتاج إليه هو أن النظام لديه 3 معرفات ملف افتراضية (أو متغيرات تشير إلى مصادر الإخراج أو الإدخال) التي تتعامل مع المدخلات والإخراج. هم انهم stdin, stdout, stderr, ، في الأعداد الصحيحة هم 0,1,2. وبعد معظم الوظائف مثل fprintf أو cout إخراج مباشرة إلى stdout.
إذا كنا نريد إعادة توجيه الإخراج، فإن طريقة واحدة تعطي، على سبيل المثال، fprintf وظيفة المزيد من الحجج تشير in و out.
ومع ذلك، هناك طريقة أكثر أناقة: يمكننا الكتابة فوق معرفات الملف الافتراضية لجعلها تشير إلى الملف الذي نريد تلقي الإخراج. dup و dup2 العمل بالضبط في هذا الموقف.
دعنا نبدأ بمثال بسيط الآن: لنفترض أننا نريد إعادة توجيه إخراج fprintf إلى ملف TXT المسمى "Chinaisbetter.txt". بادئ ذي بدء، نحتاج إلى فتح هذا الملف

int fw=open("chinaisbetter.txt", O_APPEND|O_WRONLY);

ثم نريد stdout للإشارة إلى "Chinaisbetter.txt" باستخدام وظيفة DUP:

dup2(fw,1);

الآن Stdout (1) يشير إلى واصف "Chinaisbetter.txt" على الرغم من أنه لا يزال 1، ولكن يتم إعادة توجيه الإخراج الآن.
ثم يمكنك استخدام printf كالمعتاد، ولكن النتائج ستكون في ملف TXT بدلا من إظهارها مباشرة على الشاشة:

printf("Are you kidding me? \n");

ملاحظة:

  1. هذا فقط يعطي تفسيرا بديهيا، قد تحتاج إلى التحقق من المعلومات أو معلومات مفصلة. في الواقع، نقول "نسخ" هنا، لا يقومون بنسخ كل شيء.

  2. يشير معرف الملف هنا إلى معالج الملف. واصف الملف المذكور أعلاه هو بنية معلومات ملف السجلات.

عندما تكون فضوليا حول وظائف Posix، خاصة تلك التي تبدو مكررة أنفسهم، فمن الجيد بشكل عام تحقق المعيار نفسه. وبعد في الأسفل، سترى عادة أمثلة، وكذلك المنطق وراء تنفيذ (والوجود) لكليهما.

في هذه الحالة:

الأقسام التالية تحتوي على معلومات.

أمثلة

إعادة توجيه الإخراج القياسي إلى ملف

المثال التالي يغلق الإخراج القياسي للعمليات الحالية، أعد تعيين الإخراج القياسي للذهاب إلى الملف المشار إليه بواسطة pfd, ، ويغلق واصف الملف الأصلي لتنظيف.

#include <unistd.h>
...
int pfd;
...
close(1);
dup(pfd);
close(pfd);
...

إعادة توجيه رسائل الخطأ

المثال التالي يعيد توجيه الرسائل من stderr ل stdout.

#include <unistd.h>
...
dup2(2, 1); // 2-stderr; 1-stdout
...

استخدام التطبيق

لا أحد.

الأساس المنطقي

ال dup() و dup2() وظائف زائدة عن الحاجة. يتم توفير خدماتهم أيضا من قبل fcntl() وظيفة. تم تضمينها في هذا الحجم من IEEE STD 1003.1-2001 في المقام الأول لأسباب تاريخية، لأن العديد من التطبيقات الموجودة تستخدمها.

في حين أن شريحة الرمز الموجز المعروض مشابه جدا في السلوك dup2(), ، التنفيذ المطابق بناء على المهام الأخرى المحددة في حجم IEEE STD 1003.1-2001 هو أكثر تعقيدا بشكل كبير. من الواضح الأقل هو التأثير المحتمل لوظيفة جذابة للإشارات التي يمكن استدعاءها بين الخطوات وتخصيص أو إلغاء تخصيص واصفات الملفات. يمكن تجنب ذلك عن طريق حظر الإشارات.

ال dup2() لا يتم وضع علامة على الوظيفة الزورق لأنها تقدم نسخة آمنة من النوع من الوظائف المتوفرة في إصدار غير آمن من النوع fcntl(). وبعد يتم استخدامه في Posix ADA Binding.

ال dup2() الوظيفة غير مخصصة للاستخدام في المناطق الهامة كآلية تزامن.

في وصف [EBADF]، تغطي حالة المغلفات خارج النطاق من قبل الحالة المعينة من المغفلات التي لا تكون صالحة. الأوصاف ل fildes و fildes2 مختلفة لأن النوع الوحيد من البطلان المناسب ل fildes2 هو ما إذا كان خارج النطاق؛ وهذا هو، لا يهم ما إذا كان fildes2 يشير إلى ملف مفتوح عند dup2() يتم إجراء مكالمة.

اتجاهات المستقبل

لا أحد.

أنظر أيضا

close(), fcntl(), open(), ، تعاريف قاعدة حجم IEEE STD 1003.1-2001، <unistd.h>

تغيير التاريخ

تم إصداره لأول مرة في المشكلة 1. المستمدة من العدد 1 من SVID.

مثال عملي واحد هو إعادة توجيه رسائل الإخراج إلى بعض دفق آخر مثل بعض ملف السجل. هنا هو نموذج التعليمات البرمجية لإعادة الاتجاه I / O.
يرجى الرجوع إلى المشاركة الأصلية هنا

#include <stdio.h>

main()
{
    int    fd;
    fpos_t pos;

    printf("stdout, ");

    fflush(stdout);
    fgetpos(stdout, &pos);
    fd = dup(fileno(stdout));
    freopen("stdout.out", "w", stdout);

    f();

    fflush(stdout);
    dup2(fd, fileno(stdout));
    close(fd);
    clearerr(stdout);
    fsetpos(stdout, &pos);        /* for C9X */

    printf("stdout again\n");
}

f()
{
printf("stdout in f()");
}

من المرجح أن يتم إعادة توجيه الإدخال / الإخراج في شل باستخدام مكالمات نظام DUP2 / FCNLT.

يمكننا بسهولة محاكاة $program 2>&1 > logfile.log نوع إعادة توجيه باستخدام وظيفة DUP2.

يقوم البرنامج أدناه بإعادة توجيه كل من Stdout و Stderr. إيجاد سلوك $program 2>&1 > output باستخدام DUP2.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int
main(void){
    int close_this_fd;
    dup2(close_this_fd = open("output", O_WRONLY), 1);
    dup2(1,2);
    close(close_this_fd);
    fprintf(stdout, "standard output\n");
    fprintf(stderr, "standard error\n");
    fflush(stdout);
    sleep(100); //sleep to examine the filedes in /proc/pid/fd level.
    return;
}

vagrant@precise64:/vagrant/advC$ ./a.out
^Z
[2]+  Stopped                 ./a.out
vagrant@precise64:/vagrant/advC$ cat output
standard error
standard output
vagrant@precise64:/vagrant/advC$ ll /proc/2761/fd
total 0
dr-x------ 2 vagrant vagrant  0 Jun 20 22:07 ./
dr-xr-xr-x 8 vagrant vagrant  0 Jun 20 22:07 ../
lrwx------ 1 vagrant vagrant 64 Jun 20 22:07 0 -> /dev/pts/0
l-wx------ 1 vagrant vagrant 64 Jun 20 22:07 1 -> /vagrant/advC/output
l-wx------ 1 vagrant vagrant 64 Jun 20 22:07 2 -> /vagrant/advC/output
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top