الفرق بين المراجعتين لصفحة: «Ruby/Kernel/select»
لا ملخص تعديل |
جميل-بيلوني (نقاش | مساهمات) تدقيق. |
||
(مراجعة متوسطة واحدة بواسطة مستخدم واحد آخر غير معروضة) | |||
سطر 3: | سطر 3: | ||
[[تصنيف: Ruby Method]] | [[تصنيف: Ruby Method]] | ||
[[تصنيف: Ruby Kernel]] | [[تصنيف: Ruby Kernel]] | ||
يستدعي | يستدعي التابع <code>select</code> دالة النظام <code>select(2)</code>، إذ يعمل على مراقبة المصفوفات الكائنات <code>[[Ruby/IO|IO]]</code> المعطاة، وينتظر حتى يصبح أحد تلك الكائنات أو أكثر جاهزًا للقراءة، وجاهزًا للكتابة، ومالكًا لاستثناءات معلقة (pending exceptions) على التوالي، ثم يعيد مصفوفة تحتوي على مصفوفات مكونة من الكائنات [[Ruby/IO|<code>IO</code>]] السابقة. سيعيد التابع القيمة <code>nil</code> إذا تم إعطاء قيمة للمهلة الزمنية <code>timeout</code>، ولم يكن هناك أي كائن جاهز خلال هذه الفترة. | ||
يراقب التابع <code>[[Ruby/IO/select|IO.select]]</code> المخزن المؤقت (buffer) للكائنات [[Ruby/IO|<code>IO</code>]] لاختبار قابليتها للقراءة. إذا لم يكن المخزن المؤقت [[Ruby/IO|<code>IO</code>]] فارغًا، فسيُبلغ التابع <code>IO.select</code> مباشرةً عن جاهزية الكائن للقراءة. هذه المراقبة لا تشمل إلا الكائنات [[Ruby/IO|<code>IO</code>]]، ولا تُطبَّق على الكائنات الشبيهة للكائنات [[Ruby/IO|<code>IO</code>]] مثل<code>OpenSSL::SSL::SSLSocket</code>. | |||
أفضل طريقة لاستخدام التابع [[Ruby/IO/select|<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>. تبلِّغ الوحدات (modules) عن كيف ينبغي للمُستدعي (caller) الانتظار مع التابع <code>[[Ruby/IO/select|IO.select]]</code>. في حال إطلاق <code>IO::WaitReadable</code>، فسيكون على المُستدعي أن ينتظر لأجل القراءة؛ وفي حال إطلاق <code>IO::WaitWritable</code>، فيجب على المُستدعي أن ينتظر لأجل الكتابة. | |||
لذلك، يمكن محاكاة حظر القراءة (<code>[[Ruby/IO/readpartial|readpartial]]</code>) باستخدام التابع [[Ruby/IO/read nonblock|<code>read_nonblock</code>]] والتابع <code>[[Ruby/IO/select|IO.select]]</code> على النحو التالي:<syntaxhighlight lang="ruby">begin | |||
result = io_like.read_nonblock(maxlen) | result = io_like.read_nonblock(maxlen) | ||
rescue IO::WaitReadable | rescue IO::WaitReadable | ||
سطر 19: | سطر 17: | ||
IO.select(nil, [io_like]) | IO.select(nil, [io_like]) | ||
retry | retry | ||
end</syntaxhighlight> | end</syntaxhighlight>عمومًا، يُفضل الجمع بين التوابع غير الحاجزة والتابع [[Ruby/IO/select|<code>IO.select</code>]] بالنسبة للكائنات الشبيهة بالكائن [[Ruby/IO|<code>IO</code>]]، مثل <code>OpenSSL::SSL::SSLSocket</code>، إذ يعيد تابعها <code>to_io</code> الكائن [[Ruby/IO|<code>IO</code>]] الأساسي. كما يستدعي [[Ruby/IO/select|<code>IO.select</code>]] التابع <code>to_io</code> لأجل الحصول على واصف الملف (file descriptor) المُنتظر. | ||
عمومًا، يُفضل الجمع بين التوابع غير | |||
هذا يعني | هذا يعني أنَّ الإبلاغ عن قابلية القراءة من طرف [[Ruby/IO/select|<code>IO.select</code>]] لا تعني إمكانية القراءة من الكائن <code>OpenSSL::SSL::SSLSocket</code>. | ||
على الأرجح أنّ <code>OpenSSL::SSL::SSLSocket</code> | على الأرجح أنّ <code>OpenSSL::SSL::SSLSocket</code> يخزّن مؤقتًا بعض البيانات. لكن لا يرى [[Ruby/IO/select|<code>IO.select</code>]] المخزن المؤقت (buffer)، لذلك يمكنه أن يُعطل (block) عندما لا يفعل <code>OpenSSL::SSL::SSLSocket.readpartial</code>. على أي حال، توجد حالات أكثر تعقيدًا. | ||
SSL هو | البروتوكول SSL هو عبارة عن تسلسل للسجلات (sequence of records). تتكون السجلات من عدة بايتات. لذا، يرسل الجانب البعيد من SSL سجلًا جزئيًا، ويبلِّغ التابع <code>IO.select</code> عن إمكانية القراءة، ولكن لا يمكن للكائن <code>OpenSSL::SSL::SSLSocket</code> فك تشفير البايتات، فيقوم <code>OpenSSL::SSL::SSLSocket.readpartial</code> بالتعطيل. | ||
يمكن أيضًا للجانب البعيد أن | يمكن أيضًا للجانب البعيد أن يرسل طلب SSL لإعادة تفاوض أمني، والذي سيُجبر محرك SSL المحلي على كتابة بعض البيانات. هذا يعني أنّ <code>OpenSSL::SSL::SSLSocket.readpartial</code> قد يستدعي دالة النظام <code>write</code>، ويمكنه التعطيل. في مثل هذه الحالة، يُطلق <code>OpenSSL::SSL::SSLSocket.read_nonblock</code> الاستثناء <code>IO::WaitWritable</code>، بدلاً من التعطيل. لذلك، سيكون على المتصل الانتظار إلى حين جاهزية الكتابة كما هو مذكور أعلاه. | ||
الجمع بين التوابع غير | الجمع بين التوابع غير الحاجزة والتابع <code>IO.select</code> مفيد أيضًا للمجاري (streams) مثل <code>tty</code>، ومقابس الأنابيب (pipe socket)، عندما تقرأ عدة عمليات من مجرى معيّن. | ||
وأخيرًا، لا يمكن لمطوري نواة لينكس أن يكونوا على يقين بأنّ قابلية القراءة للدالة <code>select(2)</code> تعني قابلية القراءة للدالة <code>read(2)</code> عندما تتبعها حتى ولو في نفس العملية. انظر توثيق الدالة<code>select(2)</code> في أنظمة لينكس. | |||
استدعاء <code>IO.select</code> قبل <code>IO | استدعاء <code>IO.select</code> قبل <code>IO.readpartial</code> يعمل بشكل جيد كالمعتاد، لكنه ليس الطريقة المثلى لاستخدام <code>IO.select</code>. | ||
لا تُظهر قابلية الكتابة | لا تُظهر قابلية الكتابة المُبلَّغ عنها من طرف الدالة <code>select(2)</code> عدد البايتات القابلة للكتابة. يُحجَب التابع <code>IO.write</code> إلى حين كتابة السلسلة النصية المعطاة كاملة. لذلك، يمكن أن يحجز <code>[[Ruby/IO/write|IO.write(two or more bytes)]]</code> بعد الابلاغ عن قابلية الكتابة من قبل <code>[[Ruby/IO/select|IO.select]]</code>. لتجنب الحجب، لا بد من استخدام <code>[[Ruby/IO/write nonblock|IO.write_nonblock]]</code>. | ||
يمكن محاكاة تعطيل الكتابة (<code>write</code>) باستخدام <code>write_nonblock</code> و <code>IO.select</code> كما يلي: يجب أن يتم حفظ <code>IO::WaitReadable</code> لأجل إعادة التفاوض الأمني SSL في <code>OpenSSL::SSL::SSLSocket</code>. <syntaxhighlight lang="ruby">while 0 < string.bytesize | يمكن محاكاة تعطيل الكتابة (<code>write</code>) باستخدام <code>[[Ruby/IO/write nonblock|write_nonblock]]</code> و [[Ruby/IO/select|<code>IO.select</code>]] كما يلي: يجب أن يتم حفظ <code>IO::WaitReadable</code> لأجل إعادة التفاوض الأمني للبروتوكول SSL في الكائن <code>OpenSSL::SSL::SSLSocket</code>.<syntaxhighlight lang="ruby">while 0 < string.bytesize | ||
begin | begin | ||
written = io_like.write_nonblock(string) | written = io_like.write_nonblock(string) | ||
سطر 54: | سطر 51: | ||
==المعاملات== | ==المعاملات== | ||
===<code>read_array</code>=== | ===<code>read_array</code>=== | ||
مصفوفةٌ من الكائنات <code>[[Ruby/IO|IO]]</code> التي تنتظر إلى حين جاهزيتها (واحد أو أكثر منها) للقراءة. | |||
===<code>write_array</code>=== | ===<code>write_array</code>=== | ||
مصفوفة من | مصفوفة من الكائنات [[Ruby/IO|<code>IO</code>]]، والتي تنتظر حتى جاهزيتها (واحد أو أكثر منها) للكتابة. | ||
===<code>error_array</code>=== | ===<code>error_array</code>=== | ||
مصفوفة من | مصفوفة من الكائنات [[Ruby/IO|<code>IO</code>]] التي تنتظر الاستثناءات. | ||
===<code>timeout</code>=== | ===<code>timeout</code>=== | ||
قيمة عددية تمثل مهلة الانتظار بالثانية. | |||
قيمة عددية تمثل | ==القيمة المعادة== | ||
==القيمة | تعاد مصفوفة تحتوي على مصفوفات مكونة من الكائنات [[Ruby/IO|<code>IO</code>]] المعطاة. إذا أعطي المعامل <code>timeout</code> الاختياري، ولم يكن هناك أي كائن [[Ruby/IO|<code>IO</code>]] جاهز خلال <code>timeout</code> ثانية، فستُعاد القيمة <code>nil</code>. | ||
==أمثلة== | ==أمثلة== | ||
مثال على استخدام التابع <code>select</code>: | مثال على استخدام التابع <code>select</code>:<syntaxhighlight lang="ruby">rp, wp = IO.pipe | ||
<syntaxhighlight lang="ruby">rp, wp = IO.pipe | |||
mesg = "ping " | mesg = "ping " | ||
100.times { | 100.times { | ||
سطر 89: | سطر 80: | ||
end | end | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight>سنيتج عن تنفيذ هذه الشيفرة:<syntaxhighlight lang="text">ping pong | ||
ping pong | ping pong | ||
ping pong | ping pong | ||
سطر 96: | سطر 87: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
==انظر أيضا== | ==انظر أيضا== | ||
* | *التابع <code>[[Ruby/IO/write|write]]</code>: يكتب السلسلة النصية المعطاة في الملف ثم يعيد طول السلسلة النصية المكتوبة. | ||
* | *التابع <code>[[Ruby/IO/write nonblock|write_nonblock]]</code>: يكتب السلسلة النصية المعطاة في <nowiki/>[[Ruby/IO|المجرى]] الذي استُدعي معه بعد تعيين قيمة الراية <code>O_NONBLOCK</code> الخاصة بواصف الملف (file descriptor) الأساسي ثم يعيد عدد البايتات المكتوبة. | ||
*التابع [[Ruby/IO/read nonblock|<code>read_nonblock</code>]]: يقرأ عددًا محدَّدًا من البايتات من <nowiki/>[[Ruby/IO|المجرى]] الذي استُدعي معه بعد تعيين الراية <code>O_NONBLOCK</code> لواصف الملف (file descriptor) الأساسي ثم يعيدها. | |||
==مصادر== | ==مصادر== | ||
*[http://ruby-doc.org/core-2.5.1/Kernel.html#method-i-select قسم | *[http://ruby-doc.org/core-2.5.1/Kernel.html#method-i-select قسم التابع select في الصنف Kernel في توثيق روبي الرسمي.] |
المراجعة الحالية بتاريخ 12:19، 16 نوفمبر 2018
يستدعي التابع select
دالة النظام select(2)
، إذ يعمل على مراقبة المصفوفات الكائنات IO
المعطاة، وينتظر حتى يصبح أحد تلك الكائنات أو أكثر جاهزًا للقراءة، وجاهزًا للكتابة، ومالكًا لاستثناءات معلقة (pending exceptions) على التوالي، ثم يعيد مصفوفة تحتوي على مصفوفات مكونة من الكائنات IO
السابقة. سيعيد التابع القيمة nil
إذا تم إعطاء قيمة للمهلة الزمنية 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
. تبلِّغ الوحدات (modules) عن كيف ينبغي للمُستدعي (caller) الانتظار مع التابع IO.select
. في حال إطلاق IO::WaitReadable
، فسيكون على المُستدعي أن ينتظر لأجل القراءة؛ وفي حال إطلاق IO::WaitWritable
، فيجب على المُستدعي أن ينتظر لأجل الكتابة.
لذلك، يمكن محاكاة حظر القراءة (readpartial
) باستخدام التابع read_nonblock
والتابع IO.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
عمومًا، يُفضل الجمع بين التوابع غير الحاجزة والتابع 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
المخزن المؤقت (buffer)، لذلك يمكنه أن يُعطل (block) عندما لا يفعل OpenSSL::SSL::SSLSocket.readpartial
. على أي حال، توجد حالات أكثر تعقيدًا.
البروتوكول SSL هو عبارة عن تسلسل للسجلات (sequence of records). تتكون السجلات من عدة بايتات. لذا، يرسل الجانب البعيد من SSL سجلًا جزئيًا، ويبلِّغ التابع IO.select
عن إمكانية القراءة، ولكن لا يمكن للكائن OpenSSL::SSL::SSLSocket
فك تشفير البايتات، فيقوم OpenSSL::SSL::SSLSocket.readpartial
بالتعطيل.
يمكن أيضًا للجانب البعيد أن يرسل طلب SSL لإعادة تفاوض أمني، والذي سيُجبر محرك SSL المحلي على كتابة بعض البيانات. هذا يعني أنّ OpenSSL::SSL::SSLSocket.readpartial
قد يستدعي دالة النظام write
، ويمكنه التعطيل. في مثل هذه الحالة، يُطلق OpenSSL::SSL::SSLSocket.read_nonblock
الاستثناء IO::WaitWritable
، بدلاً من التعطيل. لذلك، سيكون على المتصل الانتظار إلى حين جاهزية الكتابة كما هو مذكور أعلاه.
الجمع بين التوابع غير الحاجزة والتابع IO.select
مفيد أيضًا للمجاري (streams) مثل tty
، ومقابس الأنابيب (pipe socket)، عندما تقرأ عدة عمليات من مجرى معيّن.
وأخيرًا، لا يمكن لمطوري نواة لينكس أن يكونوا على يقين بأنّ قابلية القراءة للدالة 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
.
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
البنية العامة
select(read_array [, write_array [, error_array [, timeout]]]) → array or nil
المعاملات
read_array
مصفوفةٌ من الكائنات IO
التي تنتظر إلى حين جاهزيتها (واحد أو أكثر منها) للقراءة.
write_array
مصفوفة من الكائنات IO
، والتي تنتظر حتى جاهزيتها (واحد أو أكثر منها) للكتابة.
error_array
مصفوفة من الكائنات IO
التي تنتظر الاستثناءات.
timeout
قيمة عددية تمثل مهلة الانتظار بالثانية.
القيمة المعادة
تعاد مصفوفة تحتوي على مصفوفات مكونة من الكائنات IO
المعطاة. إذا أعطي المعامل timeout
الاختياري، ولم يكن هناك أي كائن IO
جاهز خلال timeout
ثانية، فستُعاد القيمة nil
.
أمثلة
مثال على استخدام التابع 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
انظر أيضا
- التابع
write
: يكتب السلسلة النصية المعطاة في الملف ثم يعيد طول السلسلة النصية المكتوبة. - التابع
write_nonblock
: يكتب السلسلة النصية المعطاة في المجرى الذي استُدعي معه بعد تعيين قيمة الرايةO_NONBLOCK
الخاصة بواصف الملف (file descriptor) الأساسي ثم يعيد عدد البايتات المكتوبة. - التابع
read_nonblock
: يقرأ عددًا محدَّدًا من البايتات من المجرى الذي استُدعي معه بعد تعيين الرايةO_NONBLOCK
لواصف الملف (file descriptor) الأساسي ثم يعيدها.