كيفية تمرير البيانات المعرفة من قبل المستخدم إلى مؤشر ترابط عامل باستخدام IOCP؟

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

سؤال

مرحبًا ... لقد قمت بإنشاء خادم اختبار صغير باستخدام منافذ إكمال I/O و Winsock. يمكنني الاتصال بنجاح وربط مقبض المقبس بمنفذ الانتهاء. لكنني لا أعرف كيفية تمرير هياكل البيانات المعرفة من قبل المستخدم إلى مؤشر ترابط Wroker ...

ما جربته حتى الآن هو تمرير بنية المستخدم (ULONG_PTR)&structure as مفتاح الانتهاء في جمعية الاتصال CreateIoCompletionPort()ولكن ذلك لم ينجح.

الآن حاولت تحديد بنية متداخلة واستخدام contining_record () كما هو موضح هنا http://msdn.microsoft.com/en-us/magazine/cc302334.aspx و http://msdn.microsoft.com/en-us/magazine/bb985148.aspx. لكن هذا لا يعمل أيضًا. (أحصل على قيم فظيعة لمحتويات Phelper)

لذا فإن سؤالي هو: كيف يمكنني تمرير البيانات إلى مؤشر ترابط العامل باستخدام WSARECV () ، و getQueuedCompletionStatus () وحزمة الإكمال أو الأسطوانة المتداخلة؟

تحرير: كيف يمكنني نقل "بنكات الوصلات" بنجاح؟ ... يبدو أنني حصلت على فن القيام بذلك (كما هو موضح في الروابط المذكورة أعلاه).

هنا يذهب الكود الخاص بي: (نعم ، إنه قبيح ورمز الاختبار الوحيد)

struct helper
    {
        SOCKET m_sock;
        unsigned int m_key;
        OVERLAPPED over;
    };


///////

SOCKET newSock = INVALID_SOCKET;
    WSABUF wsabuffer;
    char cbuf[250];
    wsabuffer.buf = cbuf;
    wsabuffer.len = 250;
    DWORD flags, bytesrecvd;


    while(true)
    {
        newSock = accept(AcceptorSock, NULL, NULL);
        if(newSock == INVALID_SOCKET)
            ErrorAbort("could not accept a connection");

        //associate socket with the CP
        if(CreateIoCompletionPort((HANDLE)newSock, hCompletionPort, 3,0) != hCompletionPort)
            ErrorAbort("Wrong port associated with the connection");
        else
            cout << "New Connection made and associated\n";

        helper* pHelper = new helper;
        pHelper->m_key = 3;
        pHelper->m_sock = newSock;
        memset(&(pHelper->over), 0, sizeof(OVERLAPPED));
        flags = 0;
        bytesrecvd = 0;

        if(WSARecv(newSock, &wsabuffer, 1, NULL, &flags, (OVERLAPPED*)pHelper, NULL) != 0)
        {
            if(WSAGetLastError() != WSA_IO_PENDING)
                ErrorAbort("WSARecv didnt work");
        }
    }

    //Cleanup
    CloseHandle(hCompletionPort);
    cin.get();
    return 0;
}

DWORD WINAPI ThreadProc(HANDLE h)
{
    DWORD dwNumberOfBytes = 0;
    OVERLAPPED* pOver = nullptr;
    helper* pHelper = nullptr;
    WSABUF RecvBuf;
    char cBuffer[250];
    RecvBuf.buf = cBuffer;
    RecvBuf.len = 250;
    DWORD dwRecvBytes = 0;
    DWORD dwFlags = 0;
    ULONG_PTR Key = 0;

    GetQueuedCompletionStatus(h, &dwNumberOfBytes, &Key, &pOver, INFINITE);

    //Extract helper
    pHelper = (helper*)CONTAINING_RECORD(pOver, helper, over);


    cout << "Received Overlapped item" << endl;
    if(WSARecv(pHelper->m_sock, &RecvBuf, 1, &dwRecvBytes, &dwFlags, pOver, NULL) != 0)
        cout << "Could not receive data\n";
    else
        cout << "Data Received: " << RecvBuf.buf << endl;

    ExitThread(0);
}
هل كانت مفيدة؟

المحلول

يمكنك إرسال بيانات متعددة الأغراض الخاصة بك إلى منفذ الانتهاء عبر postqueuedcompletionstatus.

ستلبي حزمة إكمال I/O مكالمة رائعة إلى وظيفة getQueuedCompletionStatus. تُرجع هذه الوظيفة مع القيم الثلاث التي تم تمريرها كمعلمات ثانية وثالثة ورابعة من المكالمة إلى postqueuedcompletionstatus. لا يستخدم النظام أو التحقق من صحة هذه القيم. على وجه الخصوص ، لا تحتاج المعلمة LPoverledged إلى الإشارة إلى بنية متداخلة.

نصائح أخرى

إذا قمت بتمرير بنيتك مثل هذا ، فيجب أن تعمل على ما يرام:

helper* pHelper = new helper;
CreateIoCompletionPort((HANDLE)newSock, hCompletionPort, (ULONG_PTR)pHelper,0);
...


helper* pHelper=NULL;
GetQueuedCompletionStatus(h, &dwNumberOfBytes, (PULONG_PTR)&pHelper, &pOver, INFINITE);

تحرير لإضافة بيانات IO:

واحدة من الميزات التي تم إساءة معاملتها بشكل متكرر في واجهات برمجة التطبيقات غير المتزامنة هي أنها لا تنسخ البنية المتداخلة ، فإنها تستخدم ببساطة واحدة المقدمة - وبالتالي فإن البنية المتداخلة التي تم إرجاعها من نقاط GetQueuedCompletionstatus إلى البنية المقدمة أصلاً. لذا:

struct helper {
  OVERLAPPED m_over;
  SOCKET     m_socket;
  UINT       m_key;
};

if(WSARecv(newSock, &wsabuffer, 1, NULL, &flags, &pHelper->m_over, NULL) != 0)

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

للقبض على البيانات على الجانب الآخر:

OVERLAPPED* pOver;
ULONG_PTR key;
if(GetQueuedCompletionStatus(h,&dw,&key,&pOver,INFINITE))
{
  // c cast
  helper* pConnData = (helper*)pOver;

على هذا الجانب ، من المهم بشكل خاص أن يكون البنية المتداخلة هي أول عضو في بنية المساعد ، حيث يجعل هذا الأمر سهلاً من التداخل* واجهات واجهة برمجة التطبيقات ، والمساعد الذي نريده بالفعل.

أستخدم إجراءات المقبس القياسية (المقبس ، إغلاق ، ربط ، قبول ، توصيل ...) لإنشاء/تدمير وإعادة القراءة/الكتابة لإدخال/إخراج لأنها تسمح باستخدام الهيكل المتداخل.

بعد قبول المقبس الخاص بك أو توصيله ، يجب أن تربطه بسياق الجلسة الذي يخدمه في تكنولوجيا المعلومات. ثم تقوم بربط المقبس الخاص بك إلى IOCP و (في المعلمة الثالثة) تزويدها بالإشارة إلى سياق الجلسة. لا يعرف IOCP ماهية هذه المرجع ولا يهتم أيضًا بهذه المسألة. المرجع للاستخدام الخاص بك بحيث عندما تحصل على IOC من خلال getQueuedCompletionStatus ، سيتم ملء المتغير الذي أشار إليه المعلمة 3 بالمرجع بحيث تجد على الفور السياق المرتبط بحدث المقبس ويمكن أن تبدأ في خدمة الحدث. عادةً ما أستخدم بنية مفهرسة تحتوي على (من بين أشياء أخرى) إعلان المقبس ، وهيكل متداخل وكذلك بيانات أخرى خاصة بالجلسة. سيكون المرجع الذي أمرره إلى CreateIoCompletionPort في المعلمة 3 هو الفهرس لعضو الهيكل الذي يحتوي على المقبس.

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

يجب أيضًا التحقق من الهيكل المتداخل ليرى أن الإدخال/الإخراج قد اكتمل بشكل صحيح.

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

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

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