الفرق بين المراجعتين لصفحة: «Ruby/IO/select»
أنشأ الصفحة ب'<noinclude>{{DISPLAYTITLE: التابع <code>select</code> الخاص بالصنف <code>IO</code> في روبي}}</noinclude> تصنيف: Ruby تصنيف:...' |
لا ملخص تعديل |
||
سطر 3: | سطر 3: | ||
[[تصنيف: Ruby Method]] | [[تصنيف: Ruby Method]] | ||
[[تصنيف: Ruby IO]] | [[تصنيف: Ruby IO]] | ||
يستدعي التابع <code>select</code> select(2). | يستدعي التابع <code>select</code> استدعاء النظام <code>select(2)</code>. ويراقب [[Ruby/Array|المصفوفة]] المعطاة المكونة من [[Ruby/IO|مجاري د/خ]] (كائنات <code>IO</code>)، وينتظر حتى يكون واحد أو أكثر من تلك المجاري جاهزا للقراءة، وجاهزا للكتابة، ويكون له استثناءات معلقة (pending exceptions) تواليًا، ثم يعيد [[Ruby/Array|مصفوفة]] مؤلفة من [[Ruby/Array|مصفوفات]] مكونة من تلك [[Ruby/IO|المجاري]]. ستعاد القيمة <code>nil</code> إذا تم إعطاء قيمة للوسيط الاختياري <code>timeout</code> (انظر فقرة البنية العامة)، ولم يكن أي من [[Ruby/IO|مجاري د/خ]] جاهزاً خلال <code>timeout</code> ثانية. | ||
يراقب التابع <code>select</code> المخزن المؤقت (buffer) ل[[Ruby/IO|مجرى د/خ]] لاختبار قابليته للقراءة. إذا لم يكن المخزن المؤقت ل[[Ruby/IO|لمجرى]] فارغًا، فسيُبلغ التابع <code>select</code> على الفور عن جاهزية القراءة. هذه المراقبة تشمل فقط [[Ruby/IO|مجاري د/خ]]. ولا تشمل الكائنات شبيهة <code>[[Ruby/IO|IO]]</code>، مثل <code>OpenSSL::SSL::SSLSocket</code>. | |||
أفضل طريقة لاستخدام التابع <code> | أفضل طريقة لاستخدام التابع <code>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>. | ||
تُبلغ<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 | |||
result = io_like.read_nonblock(maxlen) | |||
rescue IO::WaitReadable | |||
IO.select([io_like]) | |||
retry | |||
rescue IO::WaitWritable | |||
IO.select(nil, [io_like]) | |||
retry | |||
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>OpenSSL::SSL::SSLSocket</code> تخزّن مؤقتا بعض البيانات. لكن لا يرى التابع <code>select</code> المخزن المؤقت (buffer). لذلك يمكن للتابع <code>select</code> أن يُعطل (block) عندما لا يفعل <code>OpenSSL::SSL::SSLSocket#readpartial</code>. | ||
لكن توجد حالات أكثر تعقيدًا. | لكن توجد حالات أكثر تعقيدًا. | ||
SSL هو | SSL هو بروتوكول أمني، وهو عبارة عن تسلسل للسجلات (records)، والتي تتكون من عدة بايتات. يرسل الجانب البعيد من SSL سجلًا جزئيًا، فيقوم <code>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> مفيد عندما تقوم عدة عمليات بالقراءة من مجرى معيّن. كما هو الحال مثلا في الطرفية <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>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-i|write]]</code> باستخدام التابعين <code>[[Ruby/IO/write nonblock|write_nonblock]]</code> و <code>select</code>، <syntaxhighlight lang="ruby">while 0 < string.bytesize | |||
begin | |||
<code>[[Ruby// | 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</syntaxhighlight>يجب معالجة <code>[[Ruby/WaitReadable|IO::WaitReadable]]</code> لأجل إعادة التفاوض SSL في <code>OpenSSL::SSL::SSLSocket</code>. | |||
[ | |||
< | |||
<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>=== | ||
قيمة عددية تمثل عدد الثواني. | |||
==القيمة المُعادة== | ==القيمة المُعادة== | ||
يعيد التابع <code>select</code> [[Ruby/Array|مصفوفة]] مؤلفة من [[Ruby/Array|مصفوفات]] مكونة من [[Ruby/IO|مجاري د/خ]]. أو يعيد القيمة <code>nil</code> إذا تم إعطاء قيمة للوسيط الاختياري <code>timeout</code> ، ولم يكن أي من [[Ruby/IO|مجاري د/خ]] جاهزاً خلال <code>timeout</code> ثانية. | |||
==أمثلة== | ==أمثلة== | ||
مثال على استخدام التابع <code>select</code>: | مثال على استخدام التابع <code>select</code>:<syntaxhighlight lang="ruby">rp, wp = IO.pipe | ||
<syntaxhighlight lang="ruby"> | mesg = "ping " | ||
100.times { | |||
# IO.select follows IO#read. Not the best way to use IO.select. | |||
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 | |||
}</syntaxhighlight>الناتج:<syntaxhighlight lang="ruby">ping pong | |||
ping pong | |||
ping pong | |||
(snipped) | |||
ping</syntaxhighlight> | |||
==انظر أيضا== | ==انظر أيضا== | ||
*التابع <code>[[Ruby/IO/sysopen|sysopen]]</code>: يفتح التابع <code>sysopen</code> المسار المحدد، ثم يعيد واصف الملف الأساسي ك[[Ruby/Integer|عدد صحيح]]. | |||
* التابع <code>[[Ruby/IO/sysopen|sysopen]]</code>: يفتح التابع <code>sysopen</code> المسار المحدد، ثم يعيد واصف الملف الأساسي ك[[Ruby/Integer|عدد صحيح]] | |||
==مصادر== | ==مصادر== | ||
*[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 في توثيق روبي الرسمي.] |
مراجعة 01:25، 13 نوفمبر 2018
يستدعي التابع select
استدعاء النظام select(2)
. ويراقب المصفوفة المعطاة المكونة من مجاري د/خ (كائنات IO
)، وينتظر حتى يكون واحد أو أكثر من تلك المجاري جاهزا للقراءة، وجاهزا للكتابة، ويكون له استثناءات معلقة (pending exceptions) تواليًا، ثم يعيد مصفوفة مؤلفة من مصفوفات مكونة من تلك المجاري. ستعاد القيمة nil
إذا تم إعطاء قيمة للوسيط الاختياري timeout
(انظر فقرة البنية العامة)، ولم يكن أي من مجاري د/خ جاهزاً خلال 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
بدلاً من التعطيل. لذلك، سيكون على المتصِل الانتظار إلى حين جاهزية الكتابة كما هو موضح في المثل أعلاه.
الجمع بين التوابع غير المُعطلة والتابع IO.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
قيمة عددية تمثل عدد الثواني.
القيمة المُعادة
يعيد التابع select
مصفوفة مؤلفة من مصفوفات مكونة من مجاري د/خ. أو يعيد القيمة nil
إذا تم إعطاء قيمة للوسيط الاختياري timeout
، ولم يكن أي من مجاري د/خ جاهزاً خلال 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