دول مجلس التعاون الخليجي على HP-UX، والكثير من استطلاع ()، وأنابيب ()، والقضايا ملف

StackOverflow https://stackoverflow.com/questions/1029910

  •  06-07-2019
  •  | 
  •  

سؤال

وأواجه الكثير من المتاعب بناء 'الوسيط' مسجل - والقصد من ذلك هو وضعه على الطريق فوق عنصر في / البيرة / بن والتقاط كل ما يحدث من وإلى التطبيق. (أسود مربع التطبيق 3-حزب فشل FTP لسبب ما.) وبمجرد تشغيل، فإن الوسيط مفترق الطرق، وإعادة توجيه المعياري وستدين إلى / من الأنابيب التي الوالد لديه سيطرة، ومن ثم تنفيذ البرنامج في / البيرة / بن. (ضمنية، نعم، أنا أعرف، أنا سيئة).

ولكن، بمجرد أركض استطلاع ()، الامور غريبة. أفقد المؤشر إلى بلدي ملف السجل، واستطلاع على أنبوب الإخراج من طفل يلقي خطأ والقطط والكلاب تبدأ العيش معا، وهلم جرا.

ويمكن لأي شخص أن يلقي بعض الضوء على هذا؟

وهنا ما لدي حاليا ... الاستطلاع () في السؤال هو ملحوظ مع تعليق غير بادئة لسهولة من الموقع.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <time.h>
#include <sys/types.h>
#include <fcntl.h>

#define MAX_STR_LEN 1024
static int directionFlag; /* 0 = input, 1 = output */
static int eofFlag;

/* Splits the next char from the stream inFile, with extra
information logged if directionFlag swaps */
void logChar(int inFilDes, int outFilDes, FILE *logFile, int direction)
{
    char inChar = 0;
    if(read(inFilDes, &inChar, sizeof(char)) > 0)
    {

        if(direction != directionFlag)
        {
            directionFlag = direction;
            if(direction)
            {
                fprintf(logFile, "\nOUTPUT: ");
            } else {
                fprintf(logFile, "\nINPUT: ");
            }
        }

        write(outFilDes, &inChar, sizeof(char));
        fputc(inChar, stderr);
        fputc(inChar, logFile);
    } else {
        eofFlag = 1;
    }
    return;
}

int main(int argc, char* argv[])
{
    pid_t pid;

    int childInPipe[2];
    int childOutPipe[2];

    eofFlag = 0;

    /* [0] is input, [1] is output*/

    if(pipe(childInPipe) < 0 || pipe(childOutPipe) < 0) {
        fprintf(stderr,"Pipe error; aborting\n");
            exit(1);
    }

    if((pid = fork()) == -1){
        fprintf(stderr,"Fork error; aborting\n");
        exit(1);
    }

    if(pid)
    {
        /*Parent process*/

        int i;
        int errcode;
        time_t rawtime;
        struct tm * timeinfo;
        time(&rawtime);
        timeinfo=localtime(&rawtime);

        struct pollfd pollArray[2] = {
            { .fd = 0, .events = POLLIN, .revents = 0 },
            { .fd = childOutPipe[0], .events = POLLIN, .revents = 0 }
        };
        /* Yet again, 0 = input, 1 = output */

        nfds_t nfds = sizeof(struct pollfd[2]);

        close(childInPipe[0]);
        close(childOutPipe[1]);

        /* We don't want to change around the streams for this one,
        as we will be logging everything - and I do mean everything */

        FILE *logFile;
        if(!(logFile = fopen("/opt/middleman/logfile.txt", "a"))) {
            fprintf(stderr, "fopen fail on /opt/middleman/logfile.txt\n");
            exit(1);
        }

        fprintf(logFile, "Commandline: ");

        for(i=0; i < argc; i++)
        {
            fprintf(logFile, "%s ", argv[i]);
        }
        fprintf(logFile, "\nTIMESTAMP: %s\n", asctime(timeinfo));

        while(!eofFlag)
        {

// RIGHT HERE is where things go to pot
            errcode = poll(pollArray, nfds, 1);
// All following fprintf(logfile)s do nothing
            if(errcode < 0) {
                fprintf(stderr, "POLL returned with error %d!", errcode);
                eofFlag = 1;
            }
            if((pollArray[0].revents && POLLERR) & errno != EAGAIN ) {
                fprintf(stderr, "POLL on input has thrown an exception!\n");
                fprintf(stderr, "ERRNO value: %d\n", errno);
                fprintf(logFile, "POLL on input has thrown an exception!\n");
                eofFlag = 1;
            } else if(pollArray[0].revents && POLLIN) {
                logChar(pollArray[0].fd, childInPipe[1], logFile, 0);
            } else if((pollArray[1].revents && POLLERR) & errno != EAGAIN ) {
                fprintf(stderr, "POLL on output has thrown an exception!\n");
                fprintf(stderr, "ERRNO value: %d\n", errno);
                fprintf(logFile, "POLL on output has thrown an exception!\n");
                eofFlag = 1;
            } else if(pollArray[1].revents && POLLIN) {
                logChar(pollArray[1].fd, 1, logFile, 1);
            }

        }

        fclose(logFile);

    }
    else
    {
        /*Child process; switch streams and execute application*/
        int i;
        int catcherr = 0;
        char stmt[MAX_STR_LEN] = "/usr/bin/";

        close(childInPipe[1]);
        close(childOutPipe[0]);

        strcat(stmt, argv[0]);

        if(dup2(childInPipe[0],0) < 0) {
            fprintf(stderr, "dup2 threw error %d on childInPipe[0] to stdin!\n", errno);
        }
//      close(childInPipe[0]);

        if(dup2(childOutPipe[1],1) < 0)
        {
            fprintf(stderr, "dup2 threw error %d on childInPipe[1] to stdout!\n", errno);
        }

        /* Arguments need to be in a different format for execv */
        char* args[argc+1];
        for(i = 0; i < argc; i++)
        {
            args[i] = argv[i];
        }
        args[i] = (char *)0;

        fprintf(stderr, "Child setup complete, executing %s\n", stmt);
        fprintf(stdout, "Child setup complete, executing %s\n", stmt);

        if(execv(stmt, args) == -1) {
            fprintf(stderr, "execvP error!\n");
            exit(1);
        }
    }
    return 0;
}


تحرير 6/23/09 12:20

وبعد الإصلاحات، لقد حاولت لتشغيل "راية" من خلال هذا البرنامج، وهنا خرج أحصل ...

Child setup complete, executing /usr/bin/banner
POLL on output has thrown an exception!
ERRNO value: 0

وملف السجل لديها ما يلي:

Commandline: banner testing 
TIMESTAMP: Tue Jun 23 11:21:00 2009

والسبب ERRNO لديها 0 في ذلك لأن استطلاع () يعود على ما يرام. انها pollArray [1] .revents أن عاد مع وجود خطأ، وهو ما يعني childOutPipe [0] شملهم الاستطلاع عن وجود خطأ. logChar ()، بقدر ما أستطيع أن أقول، لم يحصل على استدعاء.

وانا ذاهب الى محاولة تقسيم من استطلاع () في اتصالين مختلفة.


حسنا، في استطلاع لحظة I () - حتى على ستدين، والتي لا تعود مع رسالة خطأ - أنه يقتل قدرتي على الكتابة إلى ملف السجل. أيضا، اكتشفت أن حلقة بينما () تدير عدة مرات قبل الانتخابات الانتاج يعود مع وجود خطأ في الأنبوب. أنا واثق أن تصبح على اقتناع متزايد بأن الانتخابات () هو مجرد قضية خاسرة.
فشلت كل محاولة الكتابة إلى ملف السجل بعد الانتخابات ()، حتى انتخابات ناجحة ()، مع errno لتعيين "رقم ملف سيئة". هذا حقا لا ينبغي أن يحدث. أنا بصراحة لا ارى كيف يمكن ان يكون التأثير التعامل مع ملفي.
حسنا، لذلك على ما يبدو أنا معتوه. شكرا لوضع لي على التوالي. كنت على افتراض nfds كان حجم بايت، وليس حجم المصفوفة. وهذا ما الثابتة، وفويلا! انها ليست مما أسفر عن مقتل بلدي ملف السجل التعامل مع أي أكثر من ذلك.

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

المحلول

والمشاكل الحقيقية:

1 (ولكن قاصر) مشكلة

struct pollfd pollArray[2] = {{0, POLLIN, 0}, {childOutPipe[0], POLLIN, 0}};

وأنت وضع افتراضات ربما لا مبرر لها حول النظام ومحتويات 'pollfd البنية. ويقول كل مستوى هو أنه يحتوي على (على الأقل) ثلاثة أعضاء. تقول شيئا عن الترتيب الذي تظهر.

<اقتباس فقرة>   

ويقوم رأس تحديد هيكل pollfd، التي يجب أن تشمل على الأقل من الأعضاء التالية أسماؤهم:

int    fd       The following descriptor being polled. 
short  events   The input event flags (see below). 
short  revents  The output event flags (see below). 

ومنذ كنت تستخدم C99، استخدم تدوين التهيئة أمنا:

    struct pollfd pollArray[2] =
    {
        { .fd = 0,               .events = POLLIN, .revents = 0 },
        { .fd = childOutPipe[0], .events = POLLIN, .revents = 0 },
    };

هل يمكن أن تحل محل 0 لإدخال معيار مع FILENO_STDIN من <fcntl.h>.

2 (في الكبرى) مشكلة

    nfds_t nfds = sizeof(pollArray);

وحجم مجموعة الاستطلاع هو على الارجح 16 (بايت) - على معظم ولكن ليس كل آلات (32 بت و 64 بت). كنت في حاجة إلى البعد من مجموعة استطلاع (والذي هو 2). هذا هو السبب في أفلت من الجحيم. يبحث النظام في القمامة والحصول على الخلط.

معالجة تعليق :

لتجد البعد من مجموعة محددة في ملف محلي أو وظيفة (ولكن ليس معلمة مجموعة تمريرها إلى وظيفة، ولا مجموعة محددة في ملف آخر)، واستخدام البديل من الماكرو:

#define DIM(x) (sizeof(x)/sizeof(*(x)))

وهذا الاسم تعود بالذاكرة إلى استخدام BASIC في الماضي قاتمة، بعيدة. الأسماء الأخرى التي رأيتها هي NELEMS أو ARRAY_SIZE أو DIMENSION (ترجع الى فورتران IV)، وأنا متأكد من أن هناك الكثير من الآخرين.

وما يحدث هو أن لأنك لا وضع nfds إلى 2، واستدعاء نظام يقوم بقراءة البيانات بعد مجموعة struct pollfd الفعلية، وتحاول أن تجعل من الرأس أو الذيل من الاشياء التي ليست struct pollfd. على وجه الخصوص، فمن المحتمل الكتابة إلى ما كنت قد قال ذلك هو الحقل revents من صف في مجموعة struct pollfd، ولكن المساحة الفعلية هو FILE * السجل، بحيث يتم مشدود بالكامل. وبالمثل للمتغيرات المحلية الأخرى. وبعبارة أخرى، كنت قد حصلت على تجاوز سعة المخزن المؤقت كومة - الملقب تجاوز المكدس، وهو الاسم الذي يجب أن يكون على دراية بصوت ضعيف. لكنه يحدث لأنك برمجتها.

والإصلاح:

    nfds_t nfds = DIM(pollArray);

3 (الصف المتوسط) مشكلة

   poll(pollArray, nfds, 1);
   if (errcode < 0) {

لا حفظ نتيجة poll()، وerrcode متغير أبدا تعيين قيمة، بعد أن تحقق ما هي القيمة بعد ذلك على الفور. سيكون رمز تصحيح ربما يلي:

errcode = poll(pollArray, nfds, 1);
if (errcode < 0)
{
    fprintf(stderr, "POLL returned with error %d!\n", errcode);
    eofFlag = 1;
}

ملاحظة إضافة حرف السطر إلى رسالة خطأ - كنت في حاجة إليها. أو:

if (poll(pollArray, nfds, 1) < 0)
{
    int errnum = errno;
    fprintf(stderr, "POLL returned with error (%d: %s)\n",
            errnum, strerror(errnum));
    eofFlag = 1;
}

في الحالة الثانية، وكنت تضيف '#include <errno.h> "إلى قائمة الرأس. توفير قيمة errno يحفظ ضد التغيير عن طريق المكالمات وظيفة - ولكن يمكنك اختبار فقط موثوق errno عندما وظيفة (دعوة النظام) قد فشلت. قد يترك حتى المكالمات وظيفة ناجحة errno غير صفرية. (على سبيل المثال، على بعض الأنظمة، إذا stderr لن محطة، وقيمة errno بعد مكالمة I / O هو ENOTTY، على الرغم من أن الدعوة ككل نجحت.)


تأملات السابقة

وبعض الأفكار السابقة على ما قد يكون مشكلة. أعتقد أنه لا يزال هناك بعض المعلومات المفيدة هنا.

<ديل> أظن مشكلتك هي أن poll() "الأضرار" مجموعة واصفات شملهم الاستطلاع، وكان لديك لإعادة بنائه على كل حلقة. (بعد التحقق من الصفحات اليدوية في في المجموعة المفتوحة ، يبدو أن poll() لم يكن لديك المشاكل التي select() يعاني من) وهذا هو بالتأكيد. مشكلة مع استدعاء نظام select() ذات الصلة.

وكود طفلك لا تغلق كل واصفات الملف عند ذلك يجب - كنت قد علق من أصل واحد "وثيقة ()` وهناك آخر في عداد المفقودين تماما. عندما يكون الطفل التشطي[هد] ربط الأنابيب لالمدخلات والمخرجات القياسية، وكنت لا تريد واصفات ملف إلغاء dupped لا تزال مفتوحة. العمليات لا يمكن الكشف عن EOF بشكل صحيح.

وقد يتم تطبيق تعليقات مماثلة في الأصل.

لاحظ أيضا أن عملية الإرسال قد تحتاج إلى إرسال حزم متعددة من البيانات للطفل قبل ظهور أي شيء على إخراج الطفل العادي. كما حالة متطرفة، والنظر في "sort '؛ الذي يقرأ جميع البيانات الخاصة به قبل إنشاء أي إخراج. <ديل> أنا قلق حول رمز تبديل الاتجاه، لذلك، على الرغم من أنني قد لا يهضم تماما ما تقوم به من نفسها، وتحويل الاتجاه غير مؤذية - ببساطة يكتب اتجاه جديد عندما يبدأ الكتابة في المقابلة الاتجاه من المرة السابقة.

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


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

ويمكنني انتشال التعليمات البرمجية التي تعمل مع الأنابيب إذا كنت في حاجة إليها (انظر ملفي الشخصي). نظرت إلى أنه بعد سنة أو سنتين قبل (هممم، التعديلات الأخيرة في 2005 في الواقع، على الرغم من أنني معاد في عام 2007) وكان لا يزال في العمل من أجل (أنه كتب حوالي عام 1989). ولدي أيضا التعليمات البرمجية التي تعمل على مآخذ بدلا من الأنابيب. وكانوا بحاجة الى بعض التكيف لتلائم الاحتياجات الخاصة بك. انهم بدلا المتخصصة (والنسخة الأنابيب، على وجه الخصوص، يدرك بروتوكول قاعدة بيانات خدمة العملاء ومحاولات لمعالجة الحزم كاملة من المعلومات).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top