الفرق بين المراجعتين ل"Ruby/IO/select"

من موسوعة حسوب
< Ruby‏ | IO
اذهب إلى التنقل اذهب إلى البحث
(أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE: التابع <code>select‎</code> الخاص بالصنف <code>IO</code> في روبي}}</noinclude> تصنيف: Ruby تصنيف:...')
 
ط (تعديل موضع جدول المحتويات)
 
(مراجعتان متوسطتان بواسطة مستخدمين اثنين آخرين غير معروضتين)
سطر 1: سطر 1:
<noinclude>{{DISPLAYTITLE: التابع <code>select‎</code> الخاص بالصنف <code>IO</code> في روبي}}</noinclude>
+
<noinclude>{{DISPLAYTITLE: التابع <code>IO.select‎</code> في روبي}}</noinclude>
 
[[تصنيف: Ruby]]
 
[[تصنيف: Ruby]]
 
[[تصنيف: Ruby Method]]
 
[[تصنيف: Ruby Method]]
 
[[تصنيف: Ruby IO]]
 
[[تصنيف: Ruby IO]]
يستدعي التابع <code>select</code> select(2)‎. ويقوم بمراقبة [[Ruby/Array|المصفوفة]] المعطاة المكونة من [[Ruby/IO|مجرى د/خ]] (كائنات <code>IO</code>)، وينتظر حتى يكون أحد كائنات <code>IO</code> جاهزًا للقراءة، وجاهزا للكتابة، ويكون لها استثناءات معلقة (pending exceptions) على التوالي، ثم يعيد [[Ruby/Array|مصفوفة]] تحتوي على [[Ruby/Array|مصفوفات]] مكونة من [[Ruby/IO|مجرى د/خ]] تلك كائنات <code>[[Ruby/IO|IO]]</code> السابقة. ستعاد القيمة <code>nil</code> إذا تم إعطاء قيمة للوسيط الاختياري <code>timeout</code> (انظر فقرة البنية العامة)، ولم يكن أي من [[Ruby/IO|مجريات د/خ]] كائن <code>IO</code> جاهزاً خلال <code>timeout</code> ثانية.
+
يستدعي التابع <code>select</code> استدعاء النظام <code>select(2)‎</code>. ويراقب [[Ruby/Array|المصفوفة]] المعطاة المكونة من [[Ruby/IO|مجاري د/خ]] (كائنات <code>[[Ruby/IO|IO]]</code>)، وينتظر حتى يكون واحد أو أكثر من تلك المجاري جاهزًا للقراءة، وجاهزًا للكتابة، ويكون له استثناءات معلقة (pending exceptions) على التوالي، ثم يعيد [[Ruby/Array|مصفوفة]] مؤلفة من [[Ruby/Array|مصفوفات]] مكونة من تلك [[Ruby/IO|المجاري]]. ستعاد القيمة <code>nil</code> إذا تم إعطاء قيمة للمعامل <code>timeout</code> الاختياري (انظر فقرة البنية العامة)، ولم يكن أيٌّ من [[Ruby/IO|مجاري د/خ]] جاهزًا خلال تلك المهلة الزمنية.
 +
__TOC__
 +
يراقب التابع <code>select</code> المخزن المؤقت (buffer) ل[[Ruby/IO|مجرى د/خ]] لاختبار قابليته للقراءة. إذا لم يكن المخزن المؤقت ل[[Ruby/IO|لمجرى]] فارغًا، فسيُبلغ التابع <code>select</code> مباشرةً عن جاهزيته للقراءة. هذه المراقبة تشمل فقط [[Ruby/IO|مجاري د/خ]] ولا تشمل الكائنات الشبيهة بالكائن <code>[[Ruby/IO|IO]]</code>، مثل <code>OpenSSL::SSL::SSLSocket</code>.
  
تراقب <code>IO.select</code> المخزن المؤقت (buffer) ل[[Ruby/IO|مجرى د/خ]] (كائنات <code>IO</code>) لاختبار قابليتها للقراءة. إذا لم يكن المخزن المؤقت <code>IO</code> فارغًا، فسيُبلغ <code>IO.select</code> على الفور عن جاهزية القراءة. هذا المراقبة لا تشمل إلا [[Ruby/IO|مجرى د/خ]] (كائنات <code>IO</code>). ولا تحدث للكائنات شبيهة IO مثل OpenSSL::SSL::SSLSocket.
+
أفضل طريقة لاستخدام التابع <code>select</code> هي باستدعائه بعد التوابع غير المُعطّلة (nonblocking methods)، مثل التابع <code>[[Ruby/IO/read nonblock|read_nonblock]]</code> و <code>[[Ruby/IO/write nonblock|write_nonblock]]</code> وغيرهما. تطلق تلك التوابع استثناء يُوسَّع بواسطة <code>[[Ruby/IO::WaitReadable|IO::WaitReadable]]</code> أو <code>[[Ruby/IO::WaitWritable|IO::WaitWritable]]</code>.
  
أفضل طريقة لاستخدام التابع <code>IO.select</code> هي باستدعائه بعد توابع غير مُعطّلة (nonblocking methods) مثل <code>[[Ruby/IO/read_nonblock|read_nonblock]]</code> و <code>[[Ruby/IO/write_nonblock|write_nonblock]]</code>، وغيرهما. تطلق التوابع استثناء، والذي يُوسّع بواسطة <code>IO::WaitReadable</code> أو <code>IO::WaitWritable</code>. تقوم [[Ruby/Module|الوحدات]] بالابلاغ عن كيف ينبغي للمُستدعي (caller) الانتظار مع <code>IO.select</code>. في حال إطلاق <code>IO::WaitReadable</code>، فسيكون على المُستدعي أن ينتظر لأجل القراءة. وفي حال إطلاق <code>IO::WaitWritable</code>، فيجب على المُستدعي أن ينتظر لأجل الكتابة.
+
تُبلغ <nowiki/>[[Ruby/Module|الوحدات]] عن كيف ينبغي للمُستدعي (caller) الانتظار مع التابع <code>select</code>. في حال إطلاق <code>[[Ruby/IO::WaitReadable|IO::WaitReadable]]</code>، فسيكون على المُستدعي أن ينتظر لأجل القراءة. وفي حال إطلاق <code>[[Ruby/IO::WaitWritable|IO::WaitWritable]]</code>، فيجب على المُستدعي أن ينتظر لأجل الكتابة.
  
لذلك، يمكن محاكاة حظر القراءة (<code>[[Ruby/IO/readpartial|readpartial]]</code>) باستخدام <code>[[Ruby/IO/read_nonblock|read_nonblock]]</code> و <code>IO.select</code> على النحو التالي:
+
لذلك، يمكن محاكاة حظر القراءة (<code>[[Ruby/IO/readpartial|readpartial]]</code>) باستخدام التابعين <code>[[Ruby/IO/read nonblock|read_nonblock]]</code> و <code>select</code> على النحو التالي:<syntaxhighlight lang="ruby">begin
 
+
  result = io_like.read_nonblock(maxlen)
 
+
rescue IO::WaitReadable
 
+
  IO.select([io_like])
على نحو خاص، يُفضل الجمع بين التوابع غير المُعطلة و التابع <code>IO.select</code> للكائنات المشابهة ل[[Ruby/IO|مجريات د/خ]] (<code>IO</code>)، مثل <code>OpenSSL::SSL::SSLSocket</code>. لديها التابع <code>[[Ruby/IO/to_io|to_io]]</code> الذي يعيد [[Ruby/IO|مجرى د/خ]] <code>IO</code> الأساسي. يستدعي <code>IO.select</code> التابع <code>[[Ruby/IO/to_io|to_io]]</code> لأجل الحصول على واصف الملف (file descriptor) المُنتظر.
+
  retry
 
+
rescue IO::WaitWritable
هذا يعني أن الإبلاغ عن قابلية القراءة من طرف <code>IO.select</code> لا تعني إمكانية القراءة من الكائن <code>OpenSSL::SSL::SSLSocket</code>.
+
  IO.select(nil, [io_like])
 
+
  retry
وعلى الأرجح أن <code>OpenSSL::SSL::SSLSocket</code> تخزّن مؤقتا بعض البيانات. لا يرى <code>IO.select</code> المخزن المؤقت. لذلك يمكن للتابع <code>IO.select</code> أن يُعطل عندما لا يفعل <code>OpenSSL::SSL::SSLSocket#readpartial</code>.
+
end‎</syntaxhighlight>يُفضل الجمع بين التوابع غير المُعطلة والتابع <code>select</code> عند العمل مع الكائنات الشبيهة بالصنف <code>[[Ruby/IO|IO]]</code>، مثل <code>OpenSSL::SSL::SSLSocket</code> لأنها تُعرّف التابع <code>[[Ruby/IO/to io|to_io]]</code> الذي يعيد [[Ruby/IO|مجرى د/خ]] أساسي. فالتابع <code>[[Ruby/IO/to io|to_io]]</code> يُستدعَى من قبل <code>select</code> لأجل الحصول على واصف الملف (file descriptor) المُنتظَر.
 
 
لكن توجد حالات أكثر تعقيدًا.
 
 
 
SSL هو بروتوكول، وهو عبارة عن تسلسل للسجلات (records). تتكون السجلات من عدة بايتات. لذا، يرسل الجانب البعيد من SSL سجلًا جزئيًا، يقوم <code>IO.select</code> بالابلاغ عن إمكانية القراءة، ولكن لا يمكن لـ <code>OpenSSL::SSL::SSLSocket</code> فك ترميز البايت، فيقوم <code>OpenSSL::SSL::SSLSocket#readpartial</code> بالتعطيل.
 
 
 
يمكن أيضًا للجانب البعيد أن يطلب إعادة التفاوض SSL renegotiation، والذي سيُجبر محرك SSL المحلي على كتابة بعض البيانات. هذا يعني أنّ <code>OpenSSL::SSL::SSLSocket#readpartial</code> قد ينفذ نظام الاستدعاء <code>[[Ruby/IO/write-i|write]]</code> ويمكنه الحجب. في مثل هذه الحالة، يطلق <code>OpenSSL::SSL::SSLSocket#read_nonblock</code> الاستثناء <code>[[Ruby/WaitWritable|IO::WaitWritable]]</code> بدلاً من التعطيل. لذلك، سيكون على المتصِل الانتظار إلى حين جاهزية الكتابة كما هو موضح في المثل أعلاه.
 
 
 
الجمع بين التوابع غير المُعطلة والتابع <code>IO.select</code> مفيد أيضًا للمجاري (streams) مثل tty، وأنابيب القنوات (pipe socket) عندما تقوم عدة عمليات بالقراءة من مجرى معيّن.
 
 
 
وأخيراً، لا يمكن لمطوري نواة لينكس (Linux kernel developers) أنّ قابلية القراءة select(2) تعني قابلية القراءة لـ read(2) حتى ولو في نفس العملية. انظر توثيق select(2)‎ في نظام جنو / لينكس.
 
 
 
استدعاء <code>IO.select</code> قبل <code>IO#readpartial</code> يعمل بشكل جيد كالمعتاد. لكنه ليس الطريقة الأفضل لاستخدام <code>IO.select</code>.
 
 
 
لا تُظهر قابلية الكتابة المُبلغ عنها من طرف select (2)‎ عن عدد البايتات القابلة للكتابة. يُعطِّل التابع <code>IO#write</code> إلى حين كتابة [[Ruby/String|السلسلة النصية]] المعطاة كاملة. لذلك، يمكن أن يُعطّل <code>IO#write(two or more bytes)</code> بعد الابلاغ عن قابلية الكتابة من قبل <code>IO.select</code>. لتجنب التعطيل، لا بد من استخدام <code>IO#write_nonblock</code>.
 
  
يمكن محاكاة تعطيل الكتابة (<code>[[Ruby/IO/write-i|write]]</code>) باستخدام <code>[[Ruby/IO/write_nonblock|write_nonblock]]</code> و <code>IO.select</code> كما يلي: يجب أن يتم حفظ <code>[[Ruby/WaitReadable|IO::WaitReadable]]</code> لأجل إعادة التفاوض SSL في <code>OpenSSL::SSL::SSLSocket</code>.
+
هذا يعني أن الإبلاغ عن قابلية القراءة من طرف <code>select</code> لا تعني إمكانية القراءة من الكائن <code>OpenSSL::SSL::SSLSocket</code>.
  
 +
على الأرجح أنَّ <code>OpenSSL::SSL::SSLSocket</code> تخزّن مؤقتًا بعض البيانات. لكن لا يرى التابع <code>select</code> المخزن المؤقت (buffer). لذلك، يمكن للتابع <code>select</code> أن يُعطل (block) عندما لا يفعل التابع <code>OpenSSL::SSL::SSLSocket.readpartial</code>.
  
 +
على أي حال، توجد حالات أكثر تعقيدًا.
  
الوسائط
+
SSL هو بروتوكول أمني، وهو عبارة عن تسلسل للسجلات (records)، والتي تتكون من عدة بايتات. يرسل الجانب البعيد من SSL سجلًا جزئيًا، فيقوم <code>select</code> بالابلاغ عن إمكانية القراءة، ولكن لن يتكمن <code>OpenSSL::SSL::SSLSocket</code> من فك ترميز البايت، فيقوم <code>OpenSSL::SSL::SSLSocket.readpartial</code> بالتعطيل.
<code>[[Ruby//select-label-Parameters|¶]]</code> <code>[[Ruby//top|↑]]</code>
 
  
read_array
+
يمكن أيضًا للجانب البعيد أن يطلب إعادة التفاوض (SSL renegotiation)، والذي سيُجبر محرك SSL المحلي على كتابة بعض البيانات. هذا يعني أنّ <code>OpenSSL::SSL::SSLSocket.readpartial</code> قد ينفذ نظام الاستدعاء <code>[[Ruby/IO/write-i|write]]</code> وأنه قد يُعطّل. في مثل هذه الحالة، يطلِق <code>OpenSSL::SSL::SSLSocket.read_nonblock</code> الاستثناء <code>[[Ruby/WaitWritable|IO::WaitWritable]]</code> بدلًا من التعطيل. لذلك، سيكون على المتصِل الانتظار إلى حين جاهزية الكتابة كما هو موضح في المثال أعلاه.
  
[[Ruby/Array|مصفوفة]] من [[Ruby/IO|مجريات د/خ]] (<code>IO</code>) التي تنتظر جاهزية للقراءة
+
الجمع بين التوابع غير المُعطلة والتابع <code>select</code> مفيد عندما تقرأ عدة عمليات من مجرى معيّن. كما هو الحال مثلًا في الطرفية <code>tty</code>، وأنابيب المقابس (pipe socket)ـ
  
write_array
+
وأخيرًا، لا يمكن لمطوري نواة لينكس (Linux kernel developers) أن يضمنوا أنّ قابلية قراءة <code>select(2)‎</code> تعني قابلية قراءة <code>read(2)‎</code> التالية حتى ولو في نفس العملية. انظر توثيق <code>select(2)</code>‎ في نظام جنو / لينكس.
  
[[Ruby/Array|مصفوفة]] من [[Ruby/IO|مجريات د/خ]] <code>IO</code> التي تنتظر جاهزية للكتابة
+
استدعاء التابع <code>select</code> قبل <code>[[Ruby/IO/readpartial|readpartial]]</code> مقبول لكنه ليس الطريقة الأفضل لاستخدام <code>select</code>.
  
error_array
+
لا يُظهر الإبلاغ عن قابلية الكتابة من طرف <code>select(2)‎</code> عدد البايتات القابلة للكتابة. سيقوم التابع <code>[[Ruby/IO/write|write]]</code> بالتعطيل (blocks) إلى حين كتابة [[Ruby/String|السلسلة النصية]] المعطاة كاملةً. لذلك، يمكن أن يقوم التعبير <code>[[Ruby/IO/write|write]](two or more bytes)‎</code> بالتعطيل بعد الابلاغ عن قابلية الكتابة من قبل <code>select</code>.
  
[[Ruby/Array|مصفوفة]] من [[Ruby/IO|مجريات د/خ]] <code>IO</code> التي تنتظر الاستثناءات
+
إن أردت تجنب التعطيل، فعليك استخدام <code>[[Ruby/IO/write nonblock|write_nonblock]]</code>.
  
timeout
+
يوضح المثال التالي كيف يمكن محاكاة <code>[[Ruby/IO/write-i|write]]</code> باستخدام التابعين <code>[[Ruby/IO/write nonblock|write_nonblock]]</code> و <code>select</code>: <syntaxhighlight lang="ruby">while 0 < string.bytesize
 
+
  begin
قيمة عددية تمثل عدد الثواني
+
    written = io_like.write_nonblock(string)
 
+
  rescue IO::WaitReadable
مثال
+
    IO.select([io_like])
<code>[[Ruby//select-label-Example|]]</code> <code>[[Ruby//top|]]</code>
+
    retry
 
+
  rescue IO::WaitWritable
 
+
    IO.select(nil, [io_like])
 
+
    retry
<code>produces:</code>
+
  end
 +
  string = string.byteslice(written..-1)
 +
end</syntaxhighlight>يجب معالجة <code>[[Ruby/WaitReadable|IO::WaitReadable]]</code> لأجل إعادة التفاوض SSL في <code>OpenSSL::SSL::SSLSocket</code>.
 
==البنية العامة==
 
==البنية العامة==
 
<syntaxhighlight lang="ruby">select(read_array [, write_array [, error_array [, timeout]]]) → array or nil‎</syntaxhighlight>
 
<syntaxhighlight lang="ruby">select(read_array [, write_array [, error_array [, timeout]]]) → array or nil‎</syntaxhighlight>
 
==المعاملات==
 
==المعاملات==
 
===<code>read_array‎</code>===
 
===<code>read_array‎</code>===
 +
[[Ruby/Array|مصفوفة]] من [[Ruby/IO|مجاري د/خ]] تنتظر جاهزية للقراءة.
 +
 
===<code>write_array‎</code>===
 
===<code>write_array‎</code>===
 +
[[Ruby/Array|مصفوفة]] من [[Ruby/IO|مجاري د/خ]] تنتظر جاهزية للكتابة.
 +
 
===<code>error_array‎</code>===
 
===<code>error_array‎</code>===
 +
[[Ruby/Array|مصفوفة]] من [[Ruby/IO|مجاري د/خ]] تنتظر الاستثناءات
 +
 
===<code>timeout‎</code>===
 
===<code>timeout‎</code>===
==القيمة المُعادة==
+
قيمة عددية تمثل المهلة الزمنية لانتظار المجاري بالثانية.
 +
 
 +
==القيمة المعادة==
 +
تعاد [[Ruby/Array|مصفوفة]] مؤلفة من [[Ruby/Array|مصفوفات]] من [[Ruby/IO|مجاري د/خ]]، أو تعاد القيمة <code>nil</code> إذا تم إعطاء قيمة للمعامل الاختياري <code>timeout</code> ولم يكن أي من [[Ruby/IO|مجاري د/خ]] جاهزًا خلال تلك المهلة الزمنية.
 +
 
 
==أمثلة==
 
==أمثلة==
مثال على استخدام التابع <code>select‎</code>:
+
مثال على استخدام التابع <code>select‎</code>:<syntaxhighlight lang="ruby">rp, wp = IO.pipe
<syntaxhighlight lang="ruby">begin
+
mesg = "ping "
  result = io_like.read_nonblock(maxlen)
+
100.times {
rescue IO::WaitReadable
+
  # IO.select follows IO#read.  Not the best way to use IO.select.
   IO.select([io_like])
+
   rs, ws, = IO.select([rp], [wp])
   retry
+
   if r = rs[0]
rescue IO::WaitWritable
+
    ret = r.read(5)
   IO.select(nil, [io_like])
+
    print ret
   retry
+
    case ret
end‎</syntaxhighlight>
+
    when /ping/
==انظر أيضا==
+
      mesg = "pong\n"
* التابع <code>[[Ruby/IO/readlines|readlines]]</code>: يقرأ التابع <code>readlines</code> كامل الملف المحدد بواسطة <code>name</code> (انظر فقرة البنية العامة) سطرًا سطرًا، ويعيد تلك السطور في [[Ruby/Array|مصفوفة]]. تُفصل السطو بواسطة <code>sep</code>.
+
    when /pong/
* التابع <code>[[Ruby/IO/sysopen|sysopen]]</code>: يفتح التابع <code>sysopen</code> المسار المحدد، ثم يعيد واصف الملف الأساسي ك[[Ruby/Integer|عدد صحيح]] <code>[[Ruby/Integer|Integer]]</code>.
+
      mesg = "ping "
 +
    end
 +
  end
 +
   if w = ws[0]
 +
    w.write(mesg)
 +
   end
 +
}</syntaxhighlight>الناتج:<syntaxhighlight lang="text">ping pong
 +
ping pong
 +
ping pong
 +
(snipped)
 +
ping</syntaxhighlight>
 +
==انظر أيضًا==
 +
*التابع <code>[[Ruby/IO/sysopen|sysopen]]</code>: يفتح الملف الموجود في المسار المحدد، ثم يعيد واصف الملف الأساسي ك[[Ruby/Integer|عدد صحيح]].
 +
*التابع <code>[[Ruby/IO/write nonblock|write_nonblock]]</code>: يكتب [[Ruby/String|السلسلة النصية]] المعطاة في <nowiki/>[[Ruby/IO|مجرى د/خ]] الذي استُدعي معه باستخدام استدعاء النظام <code>write(2)‎</code> بعد تعيين قيمة الراية <code>O_NONBLOCK</code> الخاصة بواصف الملف (file descriptor) الأساسي.
 +
*التابع <code>[[Ruby/IO/readpartial|readpartial]]</code>: يقرأ من <nowiki/>[[Ruby/IO|مجرى د/خ]] عددًا محدَّدًا من البايتات على الأكثر ثم يعيدها.  
 
==مصادر==
 
==مصادر==
*[http://ruby-doc.org/core-2.5.1/IO.html#method-c-select قسم التابع select‎ في الصنف IO‎ في توثيق روبي الرسمي.]
+
*[http://ruby-doc.org/core-2.5.1/IO.html#method-c-select قسم التابع select‎ في الصنف IO‎ في توثيق روبي الرسمي.]

المراجعة الحالية بتاريخ 07:33، 22 ديسمبر 2018

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

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

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

تُبلغ الوحدات عن كيف ينبغي للمُستدعي (caller) الانتظار مع التابع select. في حال إطلاق IO::WaitReadable، فسيكون على المُستدعي أن ينتظر لأجل القراءة. وفي حال إطلاق IO::WaitWritable، فيجب على المُستدعي أن ينتظر لأجل الكتابة.

لذلك، يمكن محاكاة حظر القراءة (readpartial) باستخدام التابعين read_nonblock و 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

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

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

على الأرجح أنَّ OpenSSL::SSL::SSLSocket تخزّن مؤقتًا بعض البيانات. لكن لا يرى التابع select المخزن المؤقت (buffer). لذلك، يمكن للتابع select أن يُعطل (block) عندما لا يفعل التابع OpenSSL::SSL::SSLSocket.readpartial.

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

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

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

الجمع بين التوابع غير المُعطلة والتابع select مفيد عندما تقرأ عدة عمليات من مجرى معيّن. كما هو الحال مثلًا في الطرفية tty، وأنابيب المقابس (pipe socket)ـ

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

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

لا يُظهر الإبلاغ عن قابلية الكتابة من طرف select(2)‎ عدد البايتات القابلة للكتابة. سيقوم التابع write بالتعطيل (blocks) إلى حين كتابة السلسلة النصية المعطاة كاملةً. لذلك، يمكن أن يقوم التعبير write(two or more bytes)‎ بالتعطيل بعد الابلاغ عن قابلية الكتابة من قبل select.

إن أردت تجنب التعطيل، فعليك استخدام write_nonblock.

يوضح المثال التالي كيف يمكن محاكاة write باستخدام التابعين write_nonblock و select:

while 0 < string.bytesize
  begin
    written = io_like.write_nonblock(string)
  rescue IO::WaitReadable
    IO.select([io_like])
    retry
  rescue IO::WaitWritable
    IO.select(nil, [io_like])
    retry
  end
  string = string.byteslice(written..-1)
end

يجب معالجة IO::WaitReadable لأجل إعادة التفاوض SSL في OpenSSL::SSL::SSLSocket.

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

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

المعاملات

read_array‎

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

write_array‎

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

error_array‎

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

timeout‎

قيمة عددية تمثل المهلة الزمنية لانتظار المجاري بالثانية.

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

تعاد مصفوفة مؤلفة من مصفوفات من مجاري د/خ، أو تعاد القيمة nil إذا تم إعطاء قيمة للمعامل الاختياري timeout ولم يكن أي من مجاري د/خ جاهزًا خلال تلك المهلة الزمنية.

أمثلة

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

rp, wp = IO.pipe
mesg = "ping "
100.times {
  # IO.select follows IO#read.  Not the best way to use IO.select.
  rs, ws, = IO.select([rp], [wp])
  if r = rs[0]
    ret = r.read(5)
    print ret
    case ret
    when /ping/
      mesg = "pong\n"
    when /pong/
      mesg = "ping "
    end
  end
  if w = ws[0]
    w.write(mesg)
  end
}

الناتج:

ping pong
ping pong
ping pong
(snipped)
ping

انظر أيضًا

  • التابع sysopen: يفتح الملف الموجود في المسار المحدد، ثم يعيد واصف الملف الأساسي كعدد صحيح.
  • التابع write_nonblock: يكتب السلسلة النصية المعطاة في مجرى د/خ الذي استُدعي معه باستخدام استدعاء النظام write(2)‎ بعد تعيين قيمة الراية O_NONBLOCK الخاصة بواصف الملف (file descriptor) الأساسي.
  • التابع readpartial: يقرأ من مجرى د/خ عددًا محدَّدًا من البايتات على الأكثر ثم يعيدها.

مصادر