سؤال

هل هناك طريقة لإلغاء عملية معلقة (بدون قطع الاتصال) أو تعيين مهلة لوظائف مكتبة التعزيز؟

أي.أريد تعيين مهلة لحظر المقبس في Boost asio؟

المقبس.read_some(boost::asio::buffer(pData, maxSize), error_);

مثال:أريد أن أقرأ بعضًا من المقبس، لكني أرغب في ظهور خطأ إذا مرت 10 ثوانٍ.

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

المحلول

في نظام التشغيل Linux/BSD، يتم دعم مهلة عمليات الإدخال/الإخراج على المقابس مباشرةً بواسطة نظام التشغيل.يمكن تفعيل الخيار عبر setsocktopt().لا أعرف إذا boost::asio يوفر طريقة لإعداده أو يعرض البرنامج النصي للمأخذ للسماح لك بتعيينه مباشرة - الحالة الأخيرة ليست محمولة حقًا.

من أجل الاكتمال، إليك الوصف من صفحة الرجل:

SO_RCVTIMEO و SO_SNDTIMEO

          Specify the receiving or sending  timeouts  until  reporting  an
          error.  The argument is a struct timeval.  If an input or output
          function blocks for this period of time, and data has been  sent
          or  received,  the  return  value  of  that function will be the
          amount of data transferred; if no data has been transferred  and
          the  timeout has been reached then -1 is returned with errno set
          to EAGAIN or EWOULDBLOCK just as if the socket was specified  to
          be  non-blocking.   If  the timeout is set to zero (the default)
          then the operation  will  never  timeout.   Timeouts  only  have
          effect  for system calls that perform socket I/O (e.g., read(2),
          recvmsg(2), send(2), sendmsg(2)); timeouts have  no  effect  for
          select(2), poll(2), epoll_wait(2), etc.

نصائح أخرى

وعندما سئل هذا السؤال، أعتقد لم اسيو يكن لديك أي مثال حول كيفية تحقيق ما يحتاجه OP، وهذا هو انتهاء مهلة عملية حظر مثل عملية مأخذ توصيل حظر. الآن توجد أمثلة لتظهر لك بالضبط كيفية القيام بذلك. على سبيل المثال يبدو طويلا، ولكن هذا لأنه علق جيدا. وهو يبين كيفية استخدام ioservice في "طلقة واحدة" نوع من واسطة.

وأعتقد أن المثال هو حل كبير. الحلول الأخرى هنا كسر قابلية ولا تستفيد من ioservice. إذا قابلية ليست مهمة وioservice تبدو لكثير من النفقات العامة --THEN-- يجب أن لا تستخدم اسيو. لا يهم ما، سيكون لديك ioservice خلق (تقريبا جميع وظائف اسيو تعتمد على ذلك، حتى مآخذ متزامنة) لذلك، والاستفادة منه.

مهلة لعرقلة عملية برنامج التعاون الفني اسيو

مهلة لحجب اسيو عملية UDP

تم تحديث الوثائق اسيو، حتى التحقق من ذلك للحصول على أمثلة جديدة حول كيفية التغلب على بعض استخدام اسيو "gotchas" لديهم.

هل يمكن القيام async_read وأيضا تحديد توقيت وقتك المطلوب بها. ثم إذا كان حرائق الموقت، دعوة إلغاء على كائن المقبس الخاص بك. إلا إذا حصلت القراءة الخاصة بك، يمكنك إلغاء جهاز ضبط الوقت الخاص بك. وهذا يتطلب منك استخدام كائن io_service بطبيعة الحال.

وتحرير: العثور على التعليمات البرمجية المتكررة بالنسبة لك أن تفعل ذلك

http://lists.boost.org/Archives/boost/ 2007/04 / 120339.php

وكان لي نفس السؤال، وبعد بعض البحوث، وأبسط، أنظف حل أتمكن من الخروج مع الحصول على مأخذ الأصلي الأساسي، والقيام حدد حتى كان هناك بيانات للقراءة. حدد سوف تأخذ معلمة المهلة. وبطبيعة الحال، والعمل مع مقبس الأصلي يبدأ في الذهاب ضد جهة استخدام اسيو في المقام الأول، ولكن مرة أخرى، يبدو أن هذا أنظف الطريق. بقدر ما يمكنني أن أقول، لا اسيو لا توفر وسيلة للقيام بذلك لاستخدام متزامن بسهولة. الرمز:

        // socket here is:  boost::shared_ptr<boost::asio::ip::tcp::socket> a_socket_ptr

        // Set up a timed select call, so we can handle timeout cases.

        fd_set fileDescriptorSet;
        struct timeval timeStruct;

        // set the timeout to 30 seconds
        timeStruct.tv_sec = 30;
        timeStruct.tv_usec = 0;
        FD_ZERO(&fileDescriptorSet);

        // We'll need to get the underlying native socket for this select call, in order
        // to add a simple timeout on the read:

        int nativeSocket = a_socket_ptr->native();

        FD_SET(nativeSocket,&fileDescriptorSet);

        select(nativeSocket+1,&fileDescriptorSet,NULL,NULL,&timeStruct);

        if(!FD_ISSET(nativeSocket,&fileDescriptorSet)){ // timeout

                std::string sMsg("TIMEOUT on read client data. Client IP: ");

                sMsg.append(a_socket_ptr->remote_endpoint().address().to_string());

                throw MyException(sMsg);
        }

        // now we know there's something to read, so read
        boost::system::error_code error;
        size_t iBytesRead = a_socket_ptr->read_some(boost::asio::buffer(myVector), error);

        ...

ولعل هذا سيكون مفيدا لحالتك.

وTL، DR

socket.set_option(boost::asio::detail::socket_option::integer<SOL_SOCKET, SO_RCVTIMEO>{ 200 });

والجواب الكامل هذا السؤال تبقي يجري طلب مرارا وتكرارا لسنوات عديدة. إجابات رأيت حتى الآن ضعيفة جدا. سأضيف هذه المعلومات هنا في واحد من ظهوره الأول في هذه المسألة.

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

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

1) جيد (السيئة) API المقبس القديم:

const int timeout = 200;
::setsockopt(socket.native_handle(), SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof timeout);//SO_SNDTIMEO for send ops

تجدر الإشارة تلك الخصائص: - CONST الباحث عن مهلة - على ويندوز نوع المطلوب هو في الواقع DWORD، ولكن المجموعة الحالية من المجمعين له أنه لحسن الحظ فإن نفسه، الباحث CONST ذلك العمل سواء في الفوز وPOSIX العالم. - (CONST تشار *) للقيمة. على مطلوب Windows CONST شار *، POSIX يتطلب CONST الفراغ *، في C ++ CONST شار * سوف تتحول الى CONST الفراغ * بصمت في حين أن العكس ليس صحيحا.

والمزايا: سوف يعمل، وربما تعمل دائما مثل API مقبس قديمة ومستقرة. بسيطا بما فيه الكفاية. بسرعة. العيوب: من الناحية الفنية قد يتطلب الملفات رأس المناسبة (مختلفة على الفوز وحتى النكهات UNIX مختلفة) لsetsockopt وحدات الماكرو، ولكن التنفيذ الحالي لاسيو يلوث مساحة الاسم العالمي معهم على أي حال. يتطلب متغير المهلة. لم تكتب آمنة. على ويندوز، يتطلب أن يكون مأخذ في وضع المتراكبة للعمل (والذي يستخدم تنفيذ اسيو الحالي لحسن الحظ، لكنه لا يزال تفصيل تطبيق). القبيح!

2) خيار مأخذ اسيو مخصص:

typedef boost::asio::detail::socket_option::integer<SOL_SOCKET, SO_RCVTIMEO> rcv_timeout_option; //somewhere in your headers to be used everywhere you need it
//...
socket.set_option(rcv_timeout_option{ 200 });

والمزايا: بسيطة بما فيه الكفاية. بسرعة. جميلة (مع الرموز المميزة ل typedef). العيوب: يعتمد على تفصيل تطبيق اسيو، والتي قد تتغير (ولكن OTOH كل شيء سيتغير في نهاية المطاف، ومثل هذه التفاصيل هو أقل عرضة للتغيير واجهات برمجة التطبيقات ثم العام تخضع لتوحيد). ولكن في حال حدث ذلك، سيكون لديك إما كتابة فئة وفقا ل<لأ href = "https://www.boost.org/doc/libs/1_68_0/doc/html/boost_asio/reference/SettableSocketOption.html" يختلط = "noreferrer"> https://www.boost.org/doc/libs/1_68_0/doc/html/boost_asio/reference/SettableSocketOption.html (والذي هو بطبيعة الحال بفضل PITA الرئيسية لoverengineering واضح من هذا الجزء من اسيو) أو الأفضل من ذلك تعود إلى 1.

و3) استخدام C ++ المتزامن / مرافق في المستقبل.

#include <future>
#include <chrono>
//...
auto status = std::async(std::launch::async, [&] (){ /*your stream ops*/ })
    .wait_for(std::chrono::milliseconds{ 200 });
switch (status)
    {
    case std::future_status::deferred:
    //... should never happen with std::launch::async
        break;
    case std::future_status::ready:
    //...
        break;
    case std::future_status::timeout:
    //...
        break;
    }

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

و4) طريقة المنصوص عليها اسيو - عمليات المتزامن استخدام فقط (وهي ليست حقا الإجابة على هذا السؤال)

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

متابعة لما ذكره grepsedawk.هناك بعض الأمثلة التي توضح كيفية إلغاء العمليات غير المتزامنة طويلة المدى بعد فترة من الوقت، ضمن المهلات القسم داخل اسيو دوكو. تعزيز أمثلة اسيو . لقد ساعدني عميل Async TCP أكثر من غيره.

مزامنة سعيدة :)

حتى بعد مرور سنوات على السؤال الأصلي، لا توجد إجابة مرضية حتى الآن.

لا يعد استخدام التحديد يدويًا خيارًا جيدًا

  1. يجب أن يكون رقم واصف الملف أقل من 1024
  2. قد يتم الإبلاغ عن FD بشكل زائف على أنه جاهز بسبب وجود مجموع اختباري خاطئ.

يتصل io_service.run_one() هي أيضًا فكرة سيئة، لأنه قد تكون هناك خيارات أخرى غير متزامنة تحتاج إلى خدمة io_service دائمًا run().ومن الصعب فهم مستند Boost حول حظر عميل TCP.

إذن هذا هو الحل الخاص بي.الفكرة الرئيسية هي ما يلي:

{
    Semaphore r_sem;
    boost::system::error_code r_ec;
    boost::asio::async_read(s,buffer,
                            [this, &r_ec, &r_sem](const boost::system::error_code& ec_, size_t) {
                                r_ec=ec_;
                                r_sem.notify();
                            });
    if(!r_sem.wait_for(std::chrono::seconds(3))) // wait for 3 seconds
    {
        s.cancel();
        r_sem.wait();
        throw boost::system::system_error(boost::asio::error::try_again);
    }
    else if(r_ec)
        throw boost::system::system_error(r_ec);
}

هنا Semaphore هو مجرد كائن المزامنة (mutex) وشرط_متغير.
wait_for يتم تنفيذه بواسطة http://en.cppreference.com/w/cpp/thread/condition_variable/wait_for

الكود الكامل موجود في https://github.com/scinart/cpplib/blob/master/include/asio.hpp
الأمثلة في https://github.com/scinart/cpplib/blob/master/test/test_asio.cpp
مثال أفضل في https://github.com/scinart/cpplib/blob/master/test/test_SyncBoostIO.cpp

ويمكنك لف المكالمات متزامن في العقود الآجلة وانتظر حتى إكمال مع مهلة (wait_timeout).

HTTP: // www.boost.org/doc/libs/1_47_0/doc/html/thread/synchronization.html#thread.synchronization.futures

وبالتأكيد ليس حجم واحد يناسب الجميع، ولكن يعمل بشكل جيد لمثل التحايل بطيئة ربط مهلة.

في * لا شيء، وكنت استخدام منبه () لذلك سوف تفشل دعوة المقبس الخاص بك مع EINTR

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