ما هي الطريقة الاصطلاحية للقيام ببرمجة المقبس غير المتزامن في دلفي؟

StackOverflow https://stackoverflow.com/questions/37185

سؤال

ما هي الطريقة العادية التي يكتب بها الأشخاص رمز الشبكة في دلفي لاستخدام الإدخال/الإخراج غير المتزامن للمقبس المتداخل على نمط Windows؟

إليك بحثي السابق حول هذا السؤال:

ال إندي تبدو المكونات متزامنة تمامًا.من ناحية أخرى، في حين أن وحدة ScktComp تستخدم WSAAsyncSelect، إلا أنها في الأساس لا تقوم إلا بمزامنة تطبيق مأخذ الإرسال المتعدد على نمط BSD.سيتم إغراقك في رد اتصال حدث واحد، كما لو كنت قد عدت للتو من Select() في حلقة، وسيتعين عليك القيام بكل التنقل في آلة الحالة بنفسك.

يعتبر وضع .NET أفضل إلى حد كبير، مع المقبس.BeginRead /Socket.EndRead، حيث يتم تمرير الاستمرارية مباشرة إلى المقبس.من الواضح أن الاستمرارية المرمزة كإغلاق تحتوي على كل السياق الذي تحتاجه، وأكثر من ذلك.

هل كانت مفيدة؟

المحلول

بالنسبة للأشياء غير المتزامنة، جرب ICS

http://www.overbyte.be/frame_index.html?redirTo=/products/ics.html

نصائح أخرى

لقد وجدت أن Indy، على الرغم من كونه مفهومًا أبسط في البداية، إلا أنه من الصعب إدارته بسبب الحاجة إلى قتل المقابس لتحرير الخيوط عند إنهاء التطبيق.بالإضافة إلى ذلك، توقفت مكتبة Indy عن العمل بعد ترقية تصحيح نظام التشغيل.يعمل ScktComp بشكل جيد مع طلبي.

@Roddy - المقابس المتزامنة ليست ما أبحث عنه.إن حرق مؤشر ترابط كامل من أجل اتصال ربما طويل الأمد يعني أنك تحدد مقدار الاتصالات المتزامنة بعدد سلاسل الرسائل التي يمكن أن تحتويها العملية الخاصة بك.نظرًا لأن سلاسل الرسائل تستخدم الكثير من الموارد - مساحة عنوان المكدس المحجوزة، وذاكرة المكدس المخصصة، وانتقالات kernel لمفاتيح السياق - فإنها لا تتوسع عندما تحتاج إلى دعم مئات الاتصالات، ناهيك عن الآلاف أو أكثر.

ما هي الطريقة العادية التي يكتب فيها الأشخاص رمز الشبكة في دلفي باستخدام مقبس غير متزامن على طراز Windows على طراز Windows؟

حسنًا، لقد كانت Indy هي المكتبة "القياسية" لمقبس الإدخال/الإخراج لفترة طويلة الآن - وهي تعتمد على حظر المقابس.هذا يعني أنه إذا كنت تريد سلوكًا غير متزامن، فإنك تستخدم سلسلة (سلاسل) إضافية لتوصيل/قراءة/كتابة البيانات.في رأيي، هذه في الواقع ميزة كبيرة، حيث ليست هناك حاجة لإدارة أي نوع من التنقل الآلي للحالة، أو القلق بشأن عمليات رد الاتصال أو أشياء مماثلة.أجد أن منطق موضوع "القراءة" الخاص بي أقل تشوشًا وأكثر قابلية للحمل مما تسمح به المقابس غير المحظورة.

إندي 9 لقد كان في الغالب مقاومًا للقنابل وسريعًا وموثوقًا بالنسبة لنا.لكن الانتقال إلى Indy 10 لـ Tiburon يسبب لي القليل من القلق.

@ مايك:"...الحاجة إلى قتل المقابس لتحرير المواضيع...".

جعل هذا "هاه؟" حتى تذكرت أن مكتبة الخيوط الخاصة بنا تستخدم تقنية تستند إلى الاستثناء لقتل خيوط "الانتظار" بأمان.نحن نتصل QueueUserAPC لوضع دالة في قائمة الانتظار والتي تثير استثناء C++ (غير مشتق من استثناء الفئة) والذي يجب أن يتم اكتشافه فقط من خلال إجراء غلاف مؤشر الترابط الخاص بنا.يتم استدعاء جميع المدمرات بحيث تنتهي جميع الخيوط بشكل نظيف ومرتب عند الخروج.

"المآخذ المتزامنة ليست ما أبحث عنه."

مفهوم - ولكن أعتقد في هذه الحالة أن الإجابة على سؤالك الأصلي هي أنه لا يوجد دلفي لغة. مثل لمقبس الإدخال والإخراج غير المتزامن لأنه في الواقع مطلب متخصص للغاية وغير شائع.

كمسألة جانبية، قد تجد هذه الروابط مثيرة للاهتمام.كلاهما قديم بعض الشيء وأكثر * nxy من Windows.أما السبب الثاني فيشير إلى أنه - في البيئة المناسبة - قد لا تكون الخيوط سيئة كما تعتقد.

مشكلة C10K

لماذا تعتبر الأحداث فكرة سيئة (للخوادم عالية التزامن)

@ كريس ميلر - ما ذكرته في إجابتك غير دقيق في الواقع.

يعد عدم مزامنة نمط رسائل Windows، كما هو متاح من خلال WSAAsyncSelect، بمثابة حل بديل إلى حد كبير لعدم وجود نموذج ترابط مناسب في أيام Win 3.x.

ومع ذلك، فإن .NET Begin/End هو كذلك لا باستخدام خيوط اضافية.بدلاً من ذلك، يستخدم الإدخال/الإخراج المتراكب، باستخدام الوسيطة الإضافية في WSASend / WSARecv، وتحديدًا روتين الإكمال المتراكب، لتحديد الاستمرارية.

وهذا يعني أن نمط .NET يستفيد من دعم الإدخال/الإخراج غير المتزامن لنظام التشغيل Windows يتجنب حرق الخيط عن طريق الحظر على المقبس.

نظرًا لأن سلاسل الرسائل مكلفة عمومًا (ما لم تحدد حجم مكدس صغير جدًا لـ CreateThread)، فإن حظر سلاسل الرسائل على المقابس سيمنعك من التوسع إلى 10000 ثانية من الاتصالات المتزامنة.

ولهذا السبب من المهم استخدام الإدخال/الإخراج غير المتزامن إذا كنت تريد التوسع، وأيضًا سبب أهمية .NET لا, ، وأكرر، هو لا, ، ببساطة "باستخدام المواضيع، [...] تتم إدارتها للتو بواسطة الإطار".

@Roddy - لقد قرأت بالفعل الروابط التي تشير إليها، وكلاهما تمت الإشارة إليهما من العرض التقديمي الذي قدمه Paul Tyma "آلاف الخيوط وحظر الإدخال/الإخراج - الطريقة القديمة لكتابة خوادم Java أصبحت جديدة مرة أخرى".

بعض الأشياء التي لا تنبثق بالضرورة من العرض التقديمي الذي قدمه Paul، هي أنه حدد -Xss:48k لـ JVM عند بدء التشغيل، وأنه يفترض أن تنفيذ NIO الخاص بـ JVM فعال حتى يكون صالحًا مقارنة.

إندي يفعل لا تحديد حجم مكدس متقلص ومقيد بشكل مماثل.لا توجد استدعاءات لـ BeginThread (روتين إنشاء خيط دلفي RTL، الذي يجب عليك استخدامه لمثل هذه المواقف) أو CreateThread (استدعاء WinAPI الأولي) في قاعدة تعليمات Indy.

يتم تخزين حجم المكدس الافتراضي في PE، وبالنسبة لمترجم دلفي، فإنه يكون افتراضيًا 1 ميجابايت من مساحة العنوان المحجوزة (يتم تخصيص المساحة صفحة تلو الأخرى بواسطة نظام التشغيل في أجزاء 4K؛في الواقع، يحتاج المترجم إلى إنشاء تعليمات برمجية للمس الصفحات إذا كان هناك أكثر من 4K من السكان المحليين في الوظيفة، لأن الامتداد يتم التحكم فيه عن طريق أخطاء الصفحة، ولكن فقط لأدنى صفحة (حارة) في المكدس).هذا يعني أنك ستنفد مساحة العنوان بعد أن يتعامل الحد الأقصى من 2000 مؤشر ترابط متزامن مع الاتصالات.

الآن، يمكنك تغيير حجم المكدس الافتراضي في PE باستخدام التوجيه {$M minStackSize [,maxStackSize]}، ولكن هذا سيؤثر على الجميع المواضيع، بما في ذلك الموضوع الرئيسي.أتمنى ألا تقوم بالكثير من التكرار، لأن 48 كيلو بايت أو (مشابه) لا تمثل مساحة كبيرة.

الآن، ما إذا كان بول على حق بشأن عدم أداء الإدخال/الإخراج غير المتزامن لنظام التشغيل Windows على وجه الخصوص، لست متأكدًا بنسبة 100% - يجب أن أقوم بقياسه للتأكد.ومع ذلك، ما أعرفه هو أن الحجج حول كون البرمجة المترابطة أسهل من البرمجة المبنية على الأحداث غير المتزامنة، تقدم حلاً انشطار خاطئ.

رمز غير المتزامن لا يحتاج أن تكون مبنية على الحدث؛يمكن أن يكون قائمًا على الاستمرارية، كما هو الحال في .NET، وإذا قمت بتحديد الإغلاق باعتباره استمرارًا لك، فستحصل على حالة الصيانة لك مجانًا.علاوة على ذلك، يمكن إجراء التحويل من كود نمط الخيط الخطي إلى كود غير متزامن بنمط التمرير المستمر ميكانيكيًا بواسطة مترجم (تحويل CPS ميكانيكي)، لذلك لا يلزم أن تكون هناك تكلفة في وضوح الكود أيضًا.

توجد مكونات مقبس IOCP (منافذ الإكمال) مجانية: http://www.torry.net/authorsmore.php?id=7131 (مضمنة كود المصدر)

"بواسطة نابريجنيه سيرجي ن..خادم المقبس عالي الأداء استنادًا إلى منفذ إكمال Windows ومع استخدام ملحقات Windows Socket.IPv6 مدعوم."

لقد وجدته أثناء البحث عن مكونات/مكتبة أفضل لإعادة تصميم خادم المراسلة الفورية الصغير الخاص بي.لم أجربه بعد ولكنه يبدو مشفرًا جيدًا باعتباره الانطباع الأول.

يستخدم إندي مآخذ التوصيل المتزامنة لأنها طريقة أبسط للبرمجة.كان حظر المقبس غير المتزامن شيئًا تمت إضافته إلى مكدس Winsock في أيام Windows 3.x.لم يكن Windows 3.x يدعم سلاسل الرسائل وهناك لا يمكنك إجراء إدخال/إخراج مأخذ التوصيل بدون سلاسل رسائل.للحصول على بعض المعلومات الإضافية حول سبب استخدام إندي لنموذج الحظر، يرجى الاطلاع على ذلك هذا المقال.

تستخدم مكالمات ‎.NET SwitchinRead/EndRead سلاسل العمليات، ويتم إدارتها فقط بواسطة Framework بدلاً من أنت.

@Roddy، تم دمج Indy 10 مع دلفي منذ دلفي 2006.لقد وجدت أن الانتقال من Indy 9 إلى Indy 10 هو مهمة مباشرة.

مع فئات ScktComp، تحتاج إلى استخدام خادم ThreadBlocking بدلاً من نوع خادم NonBlocking.استخدم حدث OnGetThread لتسليم معلمة ClientSocket إلى سلسلة رسائل جديدة من تصميمك.بمجرد إنشاء مثيل موروث من TServerClientThread، ستقوم بإنشاء مثيل TWinSocketStream (داخل الموضوع) والذي يمكنك استخدامه للقراءة والكتابة إلى المقبس.تمنعك هذه الطريقة من محاولة معالجة البيانات في معالج الأحداث.يمكن أن توجد هذه المواضيع لفترة قصيرة فقط تحتاج إلى القراءة أو الكتابة، أو يمكن أن تظل معلقة طوال المدة لغرض إعادة استخدامها.

موضوع كتابة خادم مأخذ التوصيل واسع إلى حد ما.هناك العديد من التقنيات والممارسات التي يمكنك اختيار تنفيذها.طريقة القراءة والكتابة على نفس المقبس الموجود في TServerClientThread هي طريقة مباشرة ورائعة للتطبيقات البسيطة.إذا كنت بحاجة إلى نموذج للإتاحة العالية والتزامن العالي، فأنت بحاجة إلى النظر في أنماط مثل نمط Proactor.

حظ سعيد!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top