يوفر لنا ظهور COM الموزعة (المشار إليها باسم DCOM) الفرصة لإنشاء تطبيقات موزعة بسهولة ؛ التطبيقات ، يمكن للمطورين تجاهل MS-RPC تقريبًا) وتطوير وظائف قوية واقتران منخفض (الوحدات الوظيفية مستقلة نسبيًا ، لقد استفاد بشكل جيد من أفكار OO) ومن السهل نشر نظام الحوسبة الموزعة.
في هذه المقالة ، نعتزم استخدام DCOM لتطوير غرفة دردشة LAN ، ليس فقط كبحث فني ، ولكن في الواقع أعتقد أن هذا يجب أن يكون أيضًا أداة مفيدة. بادئ ذي بدء ، نحتاج إلى فهم عام لوظائف غرفة الدردشة هذه:
1. على الأقل يجب أن تسمح غرفة الدردشة هذه بمستخدمي LAN المتعددين بالدردشة.
2.
3. يجب أن يكون العميل بسيطًا قدر الإمكان (دون تكوين DCOM) ، ويحتاج جانب الخادم إلى إدارة جميع سلوكيات التفاعل ، وإدارة عدد غرف الدردشة والتكوينات ذات الصلة ، والقيام بعمل جيد في مراقبة النظام وتسجيله.
4. توسيع وظائف غرفة الدردشة (مثل وظائف المحادثة الهادئة ، الرموز التعبيرية ، إلخ). استنادًا إلى الوصف الوظيفي أعلاه ، بعد تحليل المشكلة بعناية ، قمنا بتصميم المخطط التالي:
في هذه المقالة ، نريد تنفيذ جوهر أساسي لهذا البرنامج تقريبًا ، بما في ذلك Ichatmanager و TchatroomManager و Tchatroom ، لإكمال الخادم بأكثر الوظائف الأساسية وأداء اكتشاف عميل بسيط. ينصب تركيزنا على جانب الخادم ، لأنه سيقوم بتنفيذ معظم وظائف غرفة الدردشة ، والعميل مجرد برنامج صغير وبسيط.
بسبب المساحة ، ندرج فقط الرمز للأجزاء المهمة. أولاً ، دعونا نلقي نظرة على شكل واجهة Ichatmanager الخاصة بنا:
ichatmanager = واجهة (idispatch)
['{E7CD7F0D-447F-497A-8C7B-1D80E748B67F}']
الإجراء SPEATO (محتوى const: wideString ؛ DestID: integer) ؛
// يتحدث العميل إلى الغرفة المخصصة ، والرقم هو رقم الغرفة
وظيفة readfrom (SourceId: integer): istrings ؛
// يقرأ العميل محتوى المحادثة من الغرفة المخصصة ، المصدر هو رقم الغرفة
وظيفة readReady (id: integer): byte ؛
// يمكن للعميل التحقق مما إذا كانت الغرفة المحددة يمكنها بالفعل قراءة محتوى المحادثة
الإجراء ConnectRoom (const username: WideString ؛ RoomId: integer) ؛
// يقوم العملاء بتسجيل الدخول إلى غرف محددة
الإجراءات disconnectroom (const username: wideString ؛ RoomId: integer) ؛
// يخرج العميل من الغرفة المحددة
وظيفة testClearBuffertag (RoomId: عدد صحيح): عدد صحيح ؛
// يختبر العميل ما إذا كانت المنطقة العازلة للغرفة المحددة قد تم مسحها أم لا
نهاية؛
دعونا نلقي نظرة على قسم تشاتماناجر في فئة تنفيذ الواجهة:
يكتب
tchatmanager = الفصل (tautoobject ، ichatmanager)
محمية
وظيفة readfrom (SourceId: integer): istrings ؛
// هنا نستخدم tstings النوع المعقد الذي تم تمديد
// type ، Delphi يوفر واجهة isTrings
الإجراء SPEATO (محتوى const: wideString ؛ DestID: integer) ؛
وظيفة readReady (id: integer): byte ؛
// تستخدم لتزويد العميل بالاستعلام عما إذا كانت الغرفة المحددة قابلة للقراءة ، وما إذا كان المخزن المؤقت للغرفة المحدد فارغًا
الإجراء ConnectRoom (اسم المستخدم: wideString ؛ RoomId: عدد صحيح) ؛
safecall
إجراء فصل (اسم المستخدم: WideString ؛ RoomId: عدد صحيح) ؛
safecall
وظيفة testClearBuffertag (RoomId: عدد صحيح): عدد صحيح ؛
نهاية؛
جزء التنفيذ:
var
Temproom: Tchatroom ؛
يبدأ
temproom: = chatroommanager.findroombyid (sourceId) ؛
بينما temproom.locked تفعل
يبدأ
// لا شيء هو مجرد انتظار أن يتم فتحه
نهاية؛
getOlestrings (temproom.oneread ، نتيجة) ؛
نهاية؛
الإجراء tchatmanager.speakto (محتوى const: wideString ؛ destid: integer) ؛
var
Temproom: Tchatroom ؛
يبدأ
temproom: = chatroommanager.findroombyid (destid) ؛
بينما temproom.locked تفعل
يبدأ
// لا شيء هو مجرد انتظار أن يتم فتحه
نهاية؛
temproom.onespeak (المحتوى) ؛
نهاية؛
وظيفة tchatmanager.ReadReady (معرف: عدد صحيح): بايت ؛
var
Temproom: Tchatroom ؛
يبدأ
temproom: = chatroommanager.findroombyid (id) ؛
إذا temproom.canread ثم النتيجة: = 1 نتائج أخرى: = 0 ؛
نهاية؛
الإجراء tchatmanager.connectroom (const username: wideString ؛
RoomId: عدد صحيح) ؛
// يقوم العميل بتسجيل الدخول إلى الغرفة المحددة من خلال الواجهة ، ولا يتم تنفيذه بالكامل
var
Temproom: Tchatroom ؛
يبدأ
temproom: = chatroommanager.findroombyid (roomid) ؛
temproom.loginroom (اسم المستخدم) ؛
نهاية؛
الإجراء tchatmanager.disconnectroom (constame username: wideString ؛
RoomId: عدد صحيح) ؛
// يترك العميل الغرفة المحددة من خلال الواجهة ولا يتم تنفيذها بالكامل
var
Temproom: Tchatroom ؛
يبدأ
temproom: = chatroommanager.findroombyid (roomid) ؛
TempRoom.Leaveroom (اسم المستخدم) ؛
نهاية؛
وظيفة tchatmanager.testClearBuffertag (RoomId: integer): integer ؛
var
Temproom: Tchatroom ؛
يبدأ
temproom: = chatroommanager.findroombyid (roomid) ؛
النتيجة: = temproom.clearbuffertag ؛
نهاية؛
التهيئة
tautoObjectFactory.create (Comserver ، Tchatmanager ، class_chatmanager ،
cimultiinstance ، tmapartment) ؛
نهاية.
أهم tchatroom يشبه:
يكتب
tchatroom = الفصل
خاص
fbuffer: صفيف [1..20] من السلسلة ؛
fbufferlength: عدد صحيح ؛
FroomName: سلسلة ؛
Foomid: عدد صحيح.
متوفرة: Boolean ؛ // قفل متزامن ، يستخدم للتعامل مع الموقف حيث يرسل العديد من الأشخاص محادثات في نفس الوقت
fconnectcount: integer ؛ // العدد الحالي للأشخاص في الغرفة
fclearbuffertag: عدد صحيح ؛
// سوف تقفز هذه القيمة مرة واحدة في كل مرة يتم فيها مسح المخزن المؤقت ، ويتم اكتشاف هذا النبض من قبل العميل
محمية
الإجراء clearbuffer ؛ // مسح المخزن المؤقت
وظيفة getCanread: منطقية ؛
عام
إنشاء مُنشئ (اسم room: string ؛ roomid: integer) ؛
الإجراء Onespeak (المحتوى: سلسلة) ؛ // إضافة محتوى الدردشة إلى المخزن المؤقت
الإجراءات تسجيل الدخول (اسم المستخدم: سلسلة) ؛ // راجع جزء التنفيذ من التعليقات
الإجراء leaveroom (اسم المستخدم: سلسلة) ؛ // راجع جزء التنفيذ من التعليقات
وظيفة Oneread: tstrings ؛ // اقرأ السجل من المخزن المؤقت
الممتلكات المقفلة: قراءة منطقية ؛
Canread Property: Boolean Read GetCanread ؛ // تحديد ما إذا كان المخزن المؤقت فارغًا ، وإلا فإنه غير قابل للقراءة
خاصية ClearBuffertag: integer قراءة fclearbuffertag ؛
نهاية؛
تطبيق Tchatroom:
{tchatroom}
مُنشئ tchatroom.create (roomname: string ؛ roomid: integer) ؛
يبدأ
fbufferlength: = 0 ؛
fConnectCount: = 0 ؛
fclearbuffertag: = 1 ؛
توافد: = خطأ ؛
FROMNAME: = roomname ؛
Foomid: = RoomId ؛
نهاية؛
الإجراء tchatroom.clearbuffer ؛
var
أنا: عدد صحيح.
يبدأ
/// هنا يمكنك اكتشاف علامة لتحديد ما إذا كان الخادم يحتاج إلى تسجيل كل محتوى دردشة.
لأني: = 1 إلى 20 تفعل
fbuffer [i]: = '' ؛
fbufferlength: = 0 ؛
fclearbuffertag: = 0-fclearbuffertag ؛
نهاية؛
الإجراء tchatroom.onespeak (المحتوى: سلسلة) ؛
يبدأ
توافد: = صحيح ؛
INC (fbufferlength) ؛
إذا fbufferlength> 20 ثم
يبدأ
Clearbuffer
INC (fbufferlength) ؛
نهاية؛
fbuffer [fbufferLength]: = المحتوى ؛
توافد: = خطأ ؛
نهاية؛
وظيفة tchatroom.oneread: tstrings ؛
var
fstrings: tstrings.
أنا: عدد صحيح.
يبدأ
توافد: = صحيح ؛
fStrings: = tstringList.create ؛
لأني: = 1 إلى fbufferlength تفعل
fstrings.add (fbuffer [i]) ؛
النتيجة: = fStrings ؛
توافد: = خطأ ؛
نهاية؛
وظيفة tchatroom.getCanread: منطقية ؛
يبدأ
النتيجة: = خطأ ؛
إذا كان fbufferlength> 0 ثم النتيجة: = صواب ؛
نهاية؛
الإجراء tchatroom.loginroom (اسم المستخدم: سلسلة) ؛
// لم يتم تنفيذ حدث غرفة دردشة تسجيل الدخول إلى المستخدم بالكامل هنا
يبدأ
INC (fconnectcount) ؛
نهاية؛
الإجراء tchatroom.leaveroom (اسم المستخدم: سلسلة) ؛
// يترك المستخدم حدث غرفة الدردشة ، ولم يتم تنفيذه بالكامل هنا
يبدأ
ديسمبر (fconnectcount) ؛
نهاية؛
آخر جزء مهم من جانب الخادم TchatroomManager:
يكتب
tchatroommanager = الفصل
خاص
غرفة الدردشة: مجموعة من tchatroom.
عام
إنشاء مُنشئ ؛
وظيفة findroombyid (معرف: عدد صحيح): tchatroom ؛
نهاية؛
جزء التنفيذ:
{tchatroommanager}
مُنشئ tchatroommanager.create ؛
var
أنا ، Roomcount: عدد صحيح ؛
أسماء الغرفة: tstrings ؛ // Roomname هو اسم غرفة الدردشة في ملف التكوين
يبدأ
Roomcount: = 1 ؛
// هنا سنقرأ عدة غرف دردشة من ملف التكوين.
أسماء الغرفة: = tstringList.create ؛
roomNames.add ('testroom') ؛ // سيتم استبدال هذه الجملة بالقراءة النهائية من ملف التكوين.
SetLength (غرفة الدردشة ، Roomcount) ؛
لأني: = 1 إلى Roomcount
غرفة الدردشة [i]: = tchatroom.create (roomnames [i-1] ، i) ؛
نهاية؛
وظيفة tchatroommanager.findroombyid (معرف: عدد صحيح): tchatroom ؛
// تسمى هذه الوظيفة من قبل واجهة Ichatmanager ، حيث سيتم توفير النسخة النهائية من الواجهة للعميل
// وظيفة الحصول على قائمة الغرف هي حتى يعرف العميل معرف غرفته
يبدأ
النتيجة: = غرفة الدردشة [id] ؛
نهاية؛
التهيئة
chatroomManager: = tchatroommanager.create ؛
نهاية.
بعد اكتمال الجزء الأساسي الرئيسي من جانب الخادم ، نقوم بتكوين تكوين DCOM من جانب الخادم ويمكننا تطوير عميل بسيط للاختبار: (على الرغم من أن العميل بسيط قدر الإمكان ، إلا أننا لا نحتاج إلى تكوين DCOM ، لكننا ما زلنا تحتاج إلى نسخ من جانب الخادم ، لا يمكن تطوير ملف المكتبة. TLB إلا بعد تسجيل العميل.
على العميل ، ندرج وظيفتين مهمتين نسبيًا ، ويتم حذف الباقي.
الإجراء tform1.button1click (المرسل: tobject) ؛
// انقر فوق الزر 1 و "قل" محتوى التحرير
يبدأ
server.speakto (edit1.text ، 1) ؛
نهاية؛
الإجراء tform1.timer1timer (المرسل: tobject) ؛
// اطلب محتوى المحادثة من الخادم كل مرة ، وقمت بتعيينه على 1.5 ثانية
var
TempStrings: tstrings.
أنا: عدد صحيح.
يبدأ
إذا كان server.ReadReady (1) = 1 ثم
يبدأ
TempStrings: = tstringList.create ؛
setolestrings (tempstrings ، server.readfrom (1)) ؛
إذا freadstartpos> 19 ثم
إذا (fclearbuffertag = 0-server.testClearBuffertag (1)) ثم
يبدأ
freadstartpos: = 0 ؛
fclearbuffertag: = server.testClearBuffertag (1) ؛
نهاية؛
لأني: = freadstartpos إلى tempstrings.count-1 تفعل
memo1.lines.add (tempstrings [i]) ؛
freadstartpos: = tempstrings.count ؛
نهاية؛
نهاية؛
تم الانتهاء من الجزء الأساسي من غرفة دردشة LAN المستندة إلى DCOM ، وكانت جميع الاختبارات سلسة نسبيًا. القيام بذلك أيضًا.