การเกิดขึ้นของ COM แบบกระจาย (ต่อไปนี้เรียกว่า DCOM) เปิดโอกาสให้เราสร้างแอปพลิเคชันแบบกระจายได้อย่างง่ายดาย แอปพลิเคชันนักพัฒนาเกือบจะเพิกเฉยต่อ MS-RPC) และพัฒนาฟังก์ชั่นที่มีประสิทธิภาพและการมีเพศสัมพันธ์ต่ำ (โมดูลการทำงานค่อนข้างเป็นอิสระ มันใช้ประโยชน์จากความคิดของ OO เป็นอย่างดี) และง่ายต่อการปรับใช้ระบบคอมพิวเตอร์แบบกระจาย
ในบทความนี้เราตั้งใจจะใช้ DCOM เพื่อพัฒนาห้องแชท LAN ไม่เพียง แต่เป็นการวิจัยทางเทคนิค แต่จริงๆแล้วฉันเชื่อว่านี่ควรเป็นเครื่องมือที่มีประโยชน์ ก่อนอื่นเราต้องมีความเข้าใจทั่วไปเกี่ยวกับฟังก์ชั่นของห้องแชทนี้:
1. อย่างน้อยห้องแชทนี้ควรอนุญาตให้ผู้ใช้ LAN หลายคนแชท
2. ควรมีห้องแชทย่อยที่มีหลายหัวข้อและผู้ใช้สามารถเลือกเข้าห้องแชทเพื่อแชทได้
3. ไคลเอนต์ควรง่ายที่สุดเท่าที่จะทำได้ (โดยไม่ต้องกำหนดค่า DCOM) และฝั่งเซิร์ฟเวอร์จำเป็นต้องจัดการพฤติกรรมการโต้ตอบทั้งหมดจัดการจำนวนห้องแชทและการกำหนดค่าที่เกี่ยวข้องและทำงานได้ดีในการตรวจสอบและเข้าสู่ระบบระบบ
4. ขยายฟังก์ชั่นห้องสนทนา (เช่นฟังก์ชั่นการสนทนาที่เงียบสงบอิโมจิ ฯลฯ ) ตามคำอธิบายการทำงานด้านบนหลังจากวิเคราะห์ปัญหาอย่างระมัดระวังเราได้ออกแบบภาพร่างต่อไปนี้:
ในบทความนี้เราต้องการใช้แกนกลางพื้นฐานของโปรแกรมนี้รวมถึง IchatManager, Tchatroommanager และ Tchatroom เพื่อให้เซิร์ฟเวอร์สมบูรณ์ด้วยฟังก์ชั่นพื้นฐานที่สุดและทำการตรวจจับไคลเอนต์อย่างง่าย การมุ่งเน้นของเราอยู่ที่ฝั่งเซิร์ฟเวอร์เพราะมันจะใช้ฟังก์ชั่นส่วนใหญ่ของห้องแชทและไคลเอนต์เป็นเพียงโปรแกรมที่เล็กและเรียบง่ายมาก
เนื่องจากพื้นที่เราจะแสดงรายการรหัสที่สำคัญเท่านั้น ก่อนอื่นมาดูกันว่าอินเทอร์เฟซ IchatManager ของเราเป็นอย่างไร:
ichatManager = อินเทอร์เฟซ (idispatch)
['{E7CD7F0D-447F-497A-8C7B-1D80E748B67F}']
ขั้นตอนการพูด (เนื้อหา const: กว้างที่สุด; destid: จำนวนเต็ม);
// ลูกค้าพูดไปยังห้องที่กำหนดและ destid คือหมายเลขห้อง
ฟังก์ชั่น readfrom (sourceId: จำนวนเต็ม): istrings;
// ลูกค้าอ่านเนื้อหาการสนทนาจากห้องที่กำหนด SourceID คือหมายเลขห้อง
ฟังก์ชั่น ReadReady (ID: Integer): BYTE;
// ลูกค้าสามารถตรวจสอบว่าห้องที่ระบุสามารถอ่านเนื้อหาการสนทนาได้แล้ว
กระบวนการ Connectroom (ชื่อผู้ใช้ const: widestring; roomid: จำนวนเต็ม);
// ลูกค้าเข้าสู่ห้องพักที่กำหนด
ขั้นตอนการปิดเครื่อง (ชื่อผู้ใช้ const: Wridestring; RoomID: Integer);
// ลูกค้าออกจากห้องที่กำหนด
ฟังก์ชั่น TestClearBuffertag (RoomID: Integer): จำนวนเต็ม;
// การทดสอบลูกค้าว่าโซนบัฟเฟอร์ของห้องที่ระบุจะถูกล้างหรือไม่
จบ;
มาดูส่วน TCHATMANAGER ของคลาสการใช้งานอินเตอร์เฟส:
พิมพ์
tchatManager = คลาส (tautoobject, ichatmanager)
ได้รับการคุ้มครอง
ฟังก์ชั่น readfrom (sourceId: จำนวนเต็ม): istrings;
// ที่นี่เราใช้ TSTings ที่ซับซ้อนซึ่งขยายโดย Delphi เพื่อให้การสนับสนุน com นี้
// type, delphi ให้อินเทอร์เฟซ istrings
ขั้นตอนการพูด (เนื้อหา const: กว้างที่สุด; destid: จำนวนเต็ม);
ฟังก์ชั่น ReadReady (ID: Integer): BYTE;
// ใช้เพื่อให้ลูกค้าสอบถามได้ว่าห้องที่ระบุสามารถอ่านได้หรือไม่และบัฟเฟอร์ห้องที่ระบุนั้นว่างเปล่า
ขั้นตอนการเชื่อมต่อ (ชื่อผู้ใช้ const: widestring; roomid: จำนวนเต็ม);
Safecall;
ขั้นตอนการปิดระบบ (ชื่อผู้ใช้ const: widestring; roomid: จำนวนเต็ม);
Safecall;
ฟังก์ชั่น TestClearBuffertag (RoomID: Integer): จำนวนเต็ม;
จบ;
ส่วนการใช้งาน:
วาจา
Temproom: tchatroom;
เริ่ม
temproom: = chatroommanager.findroombyid (sourceid);
ในขณะที่ temproom.locked ทำ
เริ่ม
// ไม่ทำอะไรเลยที่รอการปลดล็อค
จบ;
getOleStrings (temproom.oneread, ผลลัพธ์);
จบ;
ขั้นตอน tchatManager.speakto (เนื้อหา const: กว้างที่สุด; destid: จำนวนเต็ม);
วาจา
Temproom: tchatroom;
เริ่ม
Temproom: = chatroommanager.findroombyid (destid);
ในขณะที่ temproom.locked ทำ
เริ่ม
// ไม่ทำอะไรเลยที่รอการปลดล็อค
จบ;
temproom.onespeak (เนื้อหา);
จบ;
ฟังก์ชั่น tchatmanager.readready (ID: จำนวนเต็ม): ไบต์;
วาจา
Temproom: tchatroom;
เริ่ม
Temproom: = chatroommanager.findroombyid (id);
ถ้า temproom.canread แล้วผลลัพธ์: = 1 ผลลัพธ์อื่น: = 0;
จบ;
ขั้นตอน tchatManager.Connectroom (ชื่อผู้ใช้ const: กว้างที่สุด;
RoomID: จำนวนเต็ม);
// ไคลเอนต์เข้าสู่ห้องที่ระบุผ่านอินเทอร์เฟซและไม่ได้ใช้งานอย่างสมบูรณ์
วาจา
Temproom: tchatroom;
เริ่ม
Temproom: = chatroommanager.findroombyid (roomid);
Temproom.loginroom (ชื่อผู้ใช้);
จบ;
ขั้นตอน tchatmanager.disconnectroom (ชื่อผู้ใช้ const: กว้างที่สุด;
RoomID: จำนวนเต็ม);
// ไคลเอนต์ออกจากห้องที่ระบุผ่านอินเทอร์เฟซและไม่ได้ใช้งานอย่างสมบูรณ์
วาจา
Temproom: tchatroom;
เริ่ม
Temproom: = chatroommanager.findroombyid (roomid);
Temproom.leaveroom (ชื่อผู้ใช้);
จบ;
ฟังก์ชั่น tchatmanager.testclearbuffertag (roomid: จำนวนเต็ม): จำนวนเต็ม;
วาจา
Temproom: tchatroom;
เริ่ม
Temproom: = chatroommanager.findroombyid (roomid);
ผลลัพธ์: = temproom.ClearBufferTag;
จบ;
การเริ่มต้น
tautoobjectfactory.create (comserver, tchatmanager, class_chatmanager,
cimultiinstance, tmapartment);
จบ.
tchatroom ที่สำคัญที่สุดดูเหมือนว่า:
พิมพ์
tchatroom = คลาส
ส่วนตัว
fbuffer: อาร์เรย์ [1..20] ของสตริง;
fbufferlength: จำนวนเต็ม;
Froomname: String;
Froomid: จำนวนเต็ม;
Flocked: Boolean; // Synchronous Lock ใช้เพื่อจัดการกับสถานการณ์ที่หลายคนส่งการสนทนาในเวลาเดียวกัน
fconnectCount: จำนวนเต็ม; // จำนวนคนปัจจุบันในห้อง
fclearbuffertag: จำนวนเต็ม;
// ค่านี้จะเพิ่มขึ้นทุกครั้งที่บัฟเฟอร์ถูกล้างและพัลส์นี้จะถูกตรวจพบ
ได้รับการคุ้มครอง
ขั้นตอน ClearBuffer; // ล้างบัฟเฟอร์
ฟังก์ชั่น getCanread: บูลีน;
สาธารณะ
ตัวสร้างสร้าง (RoomName: String; RoomID: Integer);
ขั้นตอน onespeak (เนื้อหา: สตริง); // เพิ่มเนื้อหาแชทลงในบัฟเฟอร์
ขั้นตอนการเข้าสู่ระบบ (ชื่อผู้ใช้: String); // อ้างถึงส่วนการใช้งานของความคิดเห็น
Procedure Leaveroom (ชื่อผู้ใช้: String); // อ้างถึงส่วนการใช้งานของความคิดเห็น
ฟังก์ชั่น oneRead: tStrings; // อ่านบันทึกจากบัฟเฟอร์
Locked Property: Boolean อ่าน Flocked;
คุณสมบัติ canread: บูลีนอ่าน getCanread; // พิจารณาว่าบัฟเฟอร์ว่างเปล่าหรือไม่มิฉะนั้นจะไม่สามารถอ่านได้
Property ClearBuffertag: จำนวนเต็มอ่าน fclearbuffertag;
จบ;
การใช้งาน tchatroom:
{tchatroom}
constructor tchatroom.create (RoomName: String; RoomID: Integer);
เริ่ม
fbufferLength: = 0;
fConnectCount: = 0;
fclearbuffertag: = 1;
แห่กัน: = เท็จ;
froomname: = roomname;
Froomid: = roomid;
จบ;
ขั้นตอน tchatroom.learbuffer;
วาจา
ฉัน: จำนวนเต็ม;
เริ่ม
/// ที่นี่คุณสามารถตรวจจับการตั้งค่าสถานะเพื่อตรวจสอบว่าเซิร์ฟเวอร์จำเป็นต้องบันทึกเนื้อหาการแชทแต่ละรายการหรือไม่
สำหรับ i: = 1 ถึง 20 ทำ
fbuffer [i]: = '';
fbufferLength: = 0;
fclearbuffertag: = 0-fclearbuffertag;
จบ;
ขั้นตอน tchatroom.onespeak (เนื้อหา: สตริง);
เริ่ม
Flocked: = true;
Inc (fbufferlength);
ถ้า fbufferlength> 20 แล้ว
เริ่ม
ClearBuffer;
Inc (fbufferlength);
จบ;
fbuffer [fbufferlength]: = เนื้อหา;
แห่กัน: = เท็จ;
จบ;
ฟังก์ชั่น tchatroom.oneread: tstrings;
วาจา
fstrings: tstrings;
ฉัน: จำนวนเต็ม;
เริ่ม
Flocked: = true;
fstrings: = tstringlist.create;
สำหรับ i: = 1 ถึง fbufferlength ทำ
fstrings.add (fbuffer [i]);
ผลลัพธ์: = fstrings;
แห่กัน: = เท็จ;
จบ;
ฟังก์ชั่น tchatroom.getCanread: บูลีน;
เริ่ม
ผลลัพธ์: = เท็จ;
ถ้า fbufferLength> 0 จากนั้นผลลัพธ์: = true;
จบ;
ขั้นตอน tchatroom.loginroom (ชื่อผู้ใช้: สตริง);
// เหตุการณ์ห้องแชทเข้าสู่ระบบของผู้ใช้ยังไม่ได้ใช้งานอย่างสมบูรณ์ที่นี่
เริ่ม
Inc (fconnectcount);
จบ;
ขั้นตอน tchatroom.leaveroom (ชื่อผู้ใช้: สตริง);
// ผู้ใช้ออกจากเหตุการณ์ในห้องแชทมันไม่ได้ถูกนำไปใช้อย่างเต็มที่ที่นี่
เริ่ม
ธ.ค. (fconnectcount);
จบ;
ส่วนสำคัญสุดท้ายของ Server Side Tchatroommanager:
พิมพ์
tChatroomManager = คลาส
ส่วนตัว
ห้องแชท: อาร์เรย์ของ Tchatroom;
สาธารณะ
ตัวสร้างสร้าง;
ฟังก์ชั่น findroombyid (ID: จำนวนเต็ม): tchatroom;
จบ;
ส่วนการใช้งาน:
{tchatroommanager}
Constructor tchatroommanager.create;
วาจา
I, RoomCount: จำนวนเต็ม;
RoomNames: tStrings; // roomname เป็นชื่อห้องแชทในไฟล์กำหนดค่า
เริ่ม
RoomCount: = 1;
// ที่นี่เราจะอ่านห้องแชทหลายห้องจากไฟล์การกำหนดค่า
RoomNames: = tStringList.create;
roomnames.add ('testroom'); // ประโยคนี้จะถูกแทนที่ด้วยการอ่านสุดท้ายจากไฟล์การกำหนดค่า
setLength (ห้องแชท, roomcount);
สำหรับ i: = 1 ถึง roomcount do
ห้องแชท [i]: = tchatroom.create (ชื่อ roomname [i-1], i);
จบ;
ฟังก์ชั่น tchatroommanager.findroombyid (ID: จำนวนเต็ม): tchatroom;
// ฟังก์ชั่นนี้เรียกโดยอินเทอร์เฟซ IchatManager เนื่องจากอินเทอร์เฟซเวอร์ชันสุดท้ายจะมอบให้กับลูกค้า
// ฟังก์ชั่นของการรับรายชื่อห้องเป็นลูกค้าจึงรู้รหัสห้องของมัน
เริ่ม
ผลลัพธ์: = ห้องแชท [id];
จบ;
การเริ่มต้น
ChatroomManager: = tchatroommanager.create;
จบ.
หลังจากส่วนหลักหลักของฝั่งเซิร์ฟเวอร์เสร็จสมบูรณ์เรากำหนดค่าการกำหนดค่า DCOM ฝั่งเซิร์ฟเวอร์และสามารถพัฒนาไคลเอนต์ง่าย ๆ สำหรับการทดสอบ: (แม้ว่าไคลเอ็นต์จะง่ายที่สุดเท่าที่จะเป็นไปได้ แต่เราไม่จำเป็นต้องกำหนดค่า DCOM แต่เรายังคง จำเป็นต้องคัดลอกประเภทฝั่งเซิร์ฟเวอร์ไฟล์ Library. TLB สามารถพัฒนาและใช้งานได้หลังจากลงทะเบียนไคลเอนต์เท่านั้น
ในลูกค้าเรามีฟังก์ชั่นที่สำคัญสองอย่างเท่านั้นและส่วนที่เหลือจะถูกละเว้น
ขั้นตอน tform1.button1click (ผู้ส่ง: tobject);
// คลิก button1 และ "พูด" เนื้อหาของการแก้ไข
เริ่ม
Server.speakto (edit1.text, 1);
จบ;
ขั้นตอน tform1.timer1timer (ผู้ส่ง: tobject);
// ขอเนื้อหาการสนทนาจากเซิร์ฟเวอร์ทุกครั้งในขณะที่และฉันตั้งค่าเป็น 1.5 วินาที
วาจา
Tempstrings: tstrings;
ฉัน: จำนวนเต็ม;
เริ่ม
ถ้า server.readready (1) = 1 แล้ว
เริ่ม
Tempstrings: = tStringList.create;
SetOleStrings (Tempstrings, Server.ReadFrom (1));
ถ้า FreadStartPos> 19 แล้ว
if (fclearbuffertag = 0-server.testclearbuffertag (1)) จากนั้น
เริ่ม
FreadStartPos: = 0;
fclearbuffertag: = server.testclearbuffertag (1);
จบ;
สำหรับ i: = freadstartpos to tempstrings.count-1 do
memo1.lines.add (tempstrings [i]);
FreadStartPos: = tempstrings.count;
จบ;
จบ;
ส่วนหลักของห้องแชท LAN ที่ใช้ DCOM นั้นเสร็จสมบูรณ์แล้วและการทดสอบทั้งหมดนั้นค่อนข้างราบรื่น ยังทำเช่นนั้น