الفرق بين المراجعتين لصفحة: «Ruby/IO/select»
لا ملخص تعديل |
جميل-بيلوني (نقاش | مساهمات) ط تعديل موضع جدول المحتويات |
||
(1 مراجعات متوسطة بواسطة نفس المستخدم غير معروضة) | |||
سطر 1: | سطر 1: | ||
<noinclude>{{DISPLAYTITLE: التابع <code>select | <noinclude>{{DISPLAYTITLE: التابع <code>IO.select</code> في روبي}}</noinclude> | ||
[[تصنيف: Ruby]] | [[تصنيف: Ruby]] | ||
[[تصنيف: Ruby Method]] | [[تصنيف: Ruby Method]] | ||
[[تصنيف: Ruby IO]] | [[تصنيف: Ruby IO]] | ||
يستدعي التابع <code>select</code> استدعاء النظام <code>select(2)</code>. ويراقب [[Ruby/Array|المصفوفة]] المعطاة المكونة من [[Ruby/IO|مجاري د/خ]] (كائنات <code>IO</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>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>. | |||
تُبلغ <nowiki/>[[Ruby/Module|الوحدات]] عن كيف ينبغي للمُستدعي (caller) الانتظار مع التابع <code>select</code>. في حال إطلاق <code>[[Ruby/IO::WaitReadable|IO::WaitReadable]]</code>، فسيكون على المُستدعي أن ينتظر لأجل القراءة. وفي حال إطلاق <code>[[Ruby/IO::WaitWritable|IO::WaitWritable]]</code>، فيجب على المُستدعي أن ينتظر لأجل الكتابة. | |||
تُبلغ<nowiki/>[[Ruby/Module|الوحدات]] عن كيف ينبغي للمُستدعي (caller) الانتظار مع التابع <code>select</code>. في حال إطلاق <code>IO::WaitReadable</code>، فسيكون على المُستدعي أن ينتظر لأجل القراءة. وفي حال إطلاق <code>IO::WaitWritable</code>، فيجب على المُستدعي أن ينتظر لأجل الكتابة. | |||
لذلك، يمكن محاكاة حظر القراءة (<code>[[Ruby/IO/readpartial|readpartial]]</code>) باستخدام التابعين <code>[[Ruby/IO/read nonblock|read_nonblock]]</code> و <code>select</code> على النحو التالي:<syntaxhighlight lang="ruby">begin | لذلك، يمكن محاكاة حظر القراءة (<code>[[Ruby/IO/readpartial|readpartial]]</code>) باستخدام التابعين <code>[[Ruby/IO/read nonblock|read_nonblock]]</code> و <code>select</code> على النحو التالي:<syntaxhighlight lang="ruby">begin | ||
سطر 19: | سطر 19: | ||
IO.select(nil, [io_like]) | IO.select(nil, [io_like]) | ||
retry | retry | ||
end</syntaxhighlight>يُفضل الجمع بين التوابع غير المُعطلة | 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) المُنتظَر. | ||
هذا يعني أن الإبلاغ عن قابلية القراءة من طرف <code>select</code> لا تعني إمكانية القراءة من الكائن <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> بالابلاغ عن إمكانية القراءة، ولكن | SSL هو بروتوكول أمني، وهو عبارة عن تسلسل للسجلات (records)، والتي تتكون من عدة بايتات. يرسل الجانب البعيد من SSL سجلًا جزئيًا، فيقوم <code>select</code> بالابلاغ عن إمكانية القراءة، ولكن لن يتكمن <code>OpenSSL::SSL::SSLSocket</code> من فك ترميز البايت، فيقوم <code>OpenSSL::SSL::SSLSocket.readpartial</code> بالتعطيل. | ||
يمكن أيضًا للجانب البعيد أن يطلب إعادة التفاوض SSL | يمكن أيضًا للجانب البعيد أن يطلب إعادة التفاوض (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> | الجمع بين التوابع غير المُعطلة والتابع <code>select</code> مفيد عندما تقرأ عدة عمليات من مجرى معيّن. كما هو الحال مثلًا في الطرفية <code>tty</code>، وأنابيب المقابس (pipe socket)ـ | ||
وأخيرًا، لا يمكن لمطوري نواة لينكس (Linux kernel developers) أن يضمنوا أنّ قابلية قراءة <code>select(2)</code> تعني قابلية قراءة <code>read(2)</code> التالية حتى ولو في نفس العملية. انظر توثيق <code>select(2)</code> في نظام جنو / لينكس. | |||
استدعاء التابع <code>select</code> قبل <code>[[Ruby/IO/readpartial|readpartial]]</code> مقبول | استدعاء التابع <code>select</code> قبل <code>[[Ruby/IO/readpartial|readpartial]]</code> مقبول لكنه ليس الطريقة الأفضل لاستخدام <code>select</code>. | ||
لا يُظهر الإبلاغ عن قابلية الكتابة من طرف <code>select (2)</code> عدد البايتات القابلة للكتابة. سيقوم التابع <code>[[Ruby/IO/write|write]]</code> بالتعطيل (blocks) إلى حين كتابة [[Ruby/String|السلسلة النصية]] المعطاة | لا يُظهر الإبلاغ عن قابلية الكتابة من طرف <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>. | ||
إن أردت تجنب التعطيل، فعليك استخدام <code>[[Ruby/IO/write nonblock|write_nonblock]]</code>. | إن أردت تجنب التعطيل، فعليك استخدام <code>[[Ruby/IO/write nonblock|write_nonblock]]</code>. | ||
يوضح المثال | يوضح المثال التالي كيف يمكن محاكاة <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 | begin | ||
written = io_like.write_nonblock(string) | written = io_like.write_nonblock(string) | ||
سطر 57: | سطر 57: | ||
==المعاملات== | ==المعاملات== | ||
===<code>read_array</code>=== | ===<code>read_array</code>=== | ||
[[Ruby/Array|مصفوفة]] من [[Ruby/IO|مجاري د/خ]] | [[Ruby/Array|مصفوفة]] من [[Ruby/IO|مجاري د/خ]] تنتظر جاهزية للقراءة. | ||
===<code>write_array</code>=== | ===<code>write_array</code>=== | ||
[[Ruby/Array|مصفوفة]] من [[Ruby/IO|مجاري د/خ]] تنتظر جاهزية للكتابة | [[Ruby/Array|مصفوفة]] من [[Ruby/IO|مجاري د/خ]] تنتظر جاهزية للكتابة. | ||
===<code>error_array</code>=== | ===<code>error_array</code>=== | ||
سطر 66: | سطر 66: | ||
===<code>timeout</code>=== | ===<code>timeout</code>=== | ||
قيمة عددية تمثل | قيمة عددية تمثل المهلة الزمنية لانتظار المجاري بالثانية. | ||
==القيمة | ==القيمة المعادة== | ||
تعاد [[Ruby/Array|مصفوفة]] مؤلفة من [[Ruby/Array|مصفوفات]] من [[Ruby/IO|مجاري د/خ]]، أو تعاد القيمة <code>nil</code> إذا تم إعطاء قيمة للمعامل الاختياري <code>timeout</code> ولم يكن أي من [[Ruby/IO|مجاري د/خ]] جاهزًا خلال تلك المهلة الزمنية. | |||
==أمثلة== | ==أمثلة== | ||
سطر 90: | سطر 90: | ||
w.write(mesg) | w.write(mesg) | ||
end | end | ||
}</syntaxhighlight>الناتج:<syntaxhighlight lang=" | }</syntaxhighlight>الناتج:<syntaxhighlight lang="text">ping pong | ||
ping pong | ping pong | ||
ping pong | ping pong | ||
(snipped) | (snipped) | ||
ping</syntaxhighlight> | ping</syntaxhighlight> | ||
==انظر | ==انظر أيضًا== | ||
*التابع <code>[[Ruby/IO/sysopen|sysopen]]</code>: يفتح | *التابع <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 قسم | *[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
: يقرأ من مجرى د/خ عددًا محدَّدًا من البايتات على الأكثر ثم يعيدها.