التابع select‎ الخاص بالصنف IO في روبي

من موسوعة حسوب
< Ruby‏ | IO
مراجعة 00:42، 13 نوفمبر 2018 بواسطة محمد-بغات (نقاش | مساهمات) (أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE: التابع <code>select‎</code> الخاص بالصنف <code>IO</code> في روبي}}</noinclude> تصنيف: Ruby تصنيف:...')
(فرق) → مراجعة أقدم | المراجعة الحالية (فرق) | مراجعة أحدث ← (فرق)

يستدعي التابع select select(2)‎. ويقوم بمراقبة المصفوفة المعطاة المكونة من مجرى د/خ (كائنات IO)، وينتظر حتى يكون أحد كائنات IO جاهزًا للقراءة، وجاهزا للكتابة، ويكون لها استثناءات معلقة (pending exceptions) على التوالي، ثم يعيد مصفوفة تحتوي على مصفوفات مكونة من مجرى د/خ تلك كائنات IO السابقة. ستعاد القيمة nil إذا تم إعطاء قيمة للوسيط الاختياري timeout (انظر فقرة البنية العامة)، ولم يكن أي من مجريات د/خ كائن IO جاهزاً خلال timeout ثانية.

تراقب IO.select المخزن المؤقت (buffer) لمجرى د/خ (كائنات IO) لاختبار قابليتها للقراءة. إذا لم يكن المخزن المؤقت IO فارغًا، فسيُبلغ IO.select على الفور عن جاهزية القراءة. هذا المراقبة لا تشمل إلا مجرى د/خ (كائنات IO). ولا تحدث للكائنات شبيهة IO مثل OpenSSL::SSL::SSLSocket.

أفضل طريقة لاستخدام التابع IO.select هي باستدعائه بعد توابع غير مُعطّلة (nonblocking methods) مثل read_nonblock و write_nonblock، وغيرهما. تطلق التوابع استثناء، والذي يُوسّع بواسطة IO::WaitReadable أو IO::WaitWritable. تقوم الوحدات بالابلاغ عن كيف ينبغي للمُستدعي (caller) الانتظار مع IO.select. في حال إطلاق IO::WaitReadable، فسيكون على المُستدعي أن ينتظر لأجل القراءة. وفي حال إطلاق IO::WaitWritable، فيجب على المُستدعي أن ينتظر لأجل الكتابة.

لذلك، يمكن محاكاة حظر القراءة (readpartial) باستخدام read_nonblock و IO.select على النحو التالي:


على نحو خاص، يُفضل الجمع بين التوابع غير المُعطلة و التابع IO.select للكائنات المشابهة لمجريات د/خ (IO)، مثل OpenSSL::SSL::SSLSocket. لديها التابع to_io الذي يعيد مجرى د/خ IO الأساسي. يستدعي IO.select التابع to_io لأجل الحصول على واصف الملف (file descriptor) المُنتظر.

هذا يعني أن الإبلاغ عن قابلية القراءة من طرف IO.select لا تعني إمكانية القراءة من الكائن OpenSSL::SSL::SSLSocket.

وعلى الأرجح أن OpenSSL::SSL::SSLSocket تخزّن مؤقتا بعض البيانات. لا يرى IO.select المخزن المؤقت. لذلك يمكن للتابع IO.select أن يُعطل عندما لا يفعل OpenSSL::SSL::SSLSocket#readpartial.

لكن توجد حالات أكثر تعقيدًا.

SSL هو بروتوكول، وهو عبارة عن تسلسل للسجلات (records). تتكون السجلات من عدة بايتات. لذا، يرسل الجانب البعيد من SSL سجلًا جزئيًا، يقوم IO.select بالابلاغ عن إمكانية القراءة، ولكن لا يمكن لـ OpenSSL::SSL::SSLSocket فك ترميز البايت، فيقوم OpenSSL::SSL::SSLSocket#readpartial بالتعطيل.

يمكن أيضًا للجانب البعيد أن يطلب إعادة التفاوض SSL renegotiation، والذي سيُجبر محرك SSL المحلي على كتابة بعض البيانات. هذا يعني أنّ OpenSSL::SSL::SSLSocket#readpartial قد ينفذ نظام الاستدعاء write ويمكنه الحجب. في مثل هذه الحالة، يطلق OpenSSL::SSL::SSLSocket#read_nonblock الاستثناء IO::WaitWritable بدلاً من التعطيل. لذلك، سيكون على المتصِل الانتظار إلى حين جاهزية الكتابة كما هو موضح في المثل أعلاه.

الجمع بين التوابع غير المُعطلة والتابع IO.select مفيد أيضًا للمجاري (streams) مثل tty، وأنابيب القنوات (pipe socket) عندما تقوم عدة عمليات بالقراءة من مجرى معيّن.

وأخيراً، لا يمكن لمطوري نواة لينكس (Linux kernel developers) أنّ قابلية القراءة select(2) تعني قابلية القراءة لـ read(2) حتى ولو في نفس العملية. انظر توثيق select(2)‎ في نظام جنو / لينكس.

استدعاء IO.select قبل IO#readpartial يعمل بشكل جيد كالمعتاد. لكنه ليس الطريقة الأفضل لاستخدام IO.select.

لا تُظهر قابلية الكتابة المُبلغ عنها من طرف select (2)‎ عن عدد البايتات القابلة للكتابة. يُعطِّل التابع IO#write إلى حين كتابة السلسلة النصية المعطاة كاملة. لذلك، يمكن أن يُعطّل IO#write(two or more bytes) بعد الابلاغ عن قابلية الكتابة من قبل IO.select. لتجنب التعطيل، لا بد من استخدام IO#write_nonblock.

يمكن محاكاة تعطيل الكتابة (write) باستخدام write_nonblock و IO.select كما يلي: يجب أن يتم حفظ IO::WaitReadable لأجل إعادة التفاوض SSL في OpenSSL::SSL::SSLSocket.


الوسائط

read_array

مصفوفة من مجريات د/خ (IO) التي تنتظر جاهزية للقراءة

write_array

مصفوفة من مجريات د/خ IO التي تنتظر جاهزية للكتابة

error_array

مصفوفة من مجريات د/خ IO التي تنتظر الاستثناءات

timeout

قيمة عددية تمثل عدد الثواني

مثال


produces:

البنية العامة

select(read_array [, write_array [, error_array [, timeout]]])  array or nil

المعاملات

read_array‎

write_array‎

error_array‎

timeout‎

القيمة المُعادة

أمثلة

مثال على استخدام التابع select‎:

begin
  result = io_like.read_nonblock(maxlen)
rescue IO::WaitReadable
  IO.select([io_like])
  retry
rescue IO::WaitWritable
  IO.select(nil, [io_like])
  retry
end

انظر أيضا

  • التابع readlines: يقرأ التابع readlines كامل الملف المحدد بواسطة name (انظر فقرة البنية العامة) سطرًا سطرًا، ويعيد تلك السطور في مصفوفة. تُفصل السطو بواسطة sep.
  • التابع sysopen: يفتح التابع sysopen المسار المحدد، ثم يعيد واصف الملف الأساسي كعدد صحيح Integer.

مصادر