1. เดลฟีและซ็อกเก็ต
เครือข่ายคอมพิวเตอร์ประกอบด้วยชุดโปรโตคอลการสื่อสารเครือข่าย โปรโตคอลหลักคือโปรโตคอล TCP/ip และ UDP ที่ชั้นการขนส่ง TCP เป็นแบบเชิงการเชื่อมต่อ และทั้งสองฝ่ายที่สื่อสารจะรักษาเส้นทาง เช่นเดียวกับสายโทรศัพท์ปัจจุบัน หากคุณใช้ telnet เพื่อเข้าสู่ระบบ BBS โปรโตคอล TCP จะถูกนำมาใช้ และฝ่ายที่สื่อสารจะไม่ดูแลแต่ละฝ่าย สถานะของผู้อื่น ใช้เมื่อเบราว์เซอร์เข้าถึงอินเทอร์เน็ต โปรโตคอล HTTP จะขึ้นอยู่กับโปรโตคอล UDP ทั้งโปรโตคอล TCP และ UDP มีความซับซ้อนมาก โดยเฉพาะโปรโตคอล TCP เพื่อให้มั่นใจถึงความถูกต้องและประสิทธิผลของการส่งผ่านเครือข่าย จะต้องดำเนินการแก้ไขข้อผิดพลาดที่ซับซ้อนและกระบวนการเรียงลำดับ
ซ็อกเก็ตเป็นข้อกำหนดของซ็อกเก็ตตามโปรโตคอลการขนส่ง (ส่วนใหญ่เป็น TCP และ UDP) เดิมเสนอโดยมหาวิทยาลัยแคลิฟอร์เนีย เบิร์กลีย์ โดยกำหนดข้อกำหนดสำหรับการสื่อสารระหว่างคอมพิวเตอร์สองเครื่อง (รวมถึงข้อกำหนดการเขียนโปรแกรมด้วย) "ช่อง" จากนั้นปลายทั้งสองของ "ช่อง" นี้จะเป็นสองช่อง ซ็อกเก็ตป้องกันความแตกต่างระหว่างซอฟต์แวร์การสื่อสารพื้นฐานและระบบปฏิบัติการเฉพาะ ทำให้สามารถสื่อสารระหว่างคอมพิวเตอร์สองเครื่องที่ติดตั้งซอฟต์แวร์โปรโตคอล TCP และใช้ข้อกำหนดเฉพาะของซ็อกเก็ตได้
ข้อมูลจำเพาะของ Windows Socket ของ Microsoft (เรียกสั้น ๆ ว่า winsock) ขยายข้อกำหนดของซ็อกเก็ตของ Berkeley คุณสามารถสื่อสารกับ Sockets บนแพลตฟอร์มใดก็ได้ โดยใช้ส่วนขยาย คุณสามารถนำไปใช้ได้อย่างมีประสิทธิภาพมากขึ้นบนแพลตฟอร์ม Windows ใน Delphi ซ็อกเก็ตพื้นฐานควรเป็นซ็อกเก็ต Windows ด้วย ซ็อกเก็ตช่วยลดความยากในการเขียนซอฟต์แวร์การสื่อสารระหว่างคอมพิวเตอร์ แต่โดยทั่วไปยังคงค่อนข้างซับซ้อน (ซึ่งจะกล่าวถึงในรายละเอียดในภายหลัง) InPRise สรุปซ็อกเก็ต Windows ใน Delphi ได้อย่างมีประสิทธิภาพทำให้ผู้ใช้สามารถเขียนโปรแกรมการสื่อสารเครือข่ายได้อย่างง่ายดาย ด้านล่างนี้เราจะอธิบายพร้อมตัวอย่างวิธีใช้ Socket เพื่อเขียนโปรแกรมการสื่อสารใน Delphi
2. ใช้ Delphi เพื่อเขียนโปรแกรมสื่อสาร Socket
ต่อไปนี้เป็นโปรแกรมสื่อสารซ็อกเก็ตอย่างง่ายซึ่งไคลเอนต์และเซิร์ฟเวอร์เป็นโปรแกรมเดียวกัน เมื่อไคลเอนต์ (เซิร์ฟเวอร์) ป้อนข้อความในบันทึกช่วยจำ 1 และกด Enter ข้อความจะสามารถแสดงบนเซิร์ฟเวอร์ (ไคลเอนต์) ) ใน memo2 สิ่งที่ตรงกันข้ามก็เป็นจริงเช่นกัน ขั้นตอนเฉพาะมีดังนี้:
1. สร้างแบบฟอร์มใหม่และตั้งชื่อตามใจชอบ เช่น วางเมนูหลัก (ในคอลัมน์มาตรฐาน) และสร้างรายการเมนู ListenItem, ConnectItem, Disconnect และ Exit; เพิ่มลงใน chatForm โดยที่ชื่อของ TClientSocket ถูกตั้งค่าเป็น ClientSocket ตั้งค่าพอร์ตเป็น 1025 ค่าดีฟอลต์แอคทีฟเป็นเท็จ ตั้งชื่อ TServerSocket เป็น ServerSocket ตั้งค่าพอร์ตเป็น 1025 ค่าดีฟอลต์แอคทีฟเป็นเท็จ และปล่อยให้ค่าอื่น ๆ ไม่เปลี่ยนแปลง จากนั้นใส่บันทึกช่วยจำสองรายการ หนึ่งชื่อ memo1 และ อื่น ๆ สำหรับ memo2 สีของ memo2 จะถูกตั้งค่าเป็นสีเทาเนื่องจากส่วนใหญ่จะใช้เพื่อแสดงอินพุตของอีกฝ่าย ด้านล่างนี้เราจะอธิบายเหตุผลขณะเขียนโค้ด
2. ดับเบิลคลิก ListemItem เขียนโค้ดต่อไปนี้:
ขั้นตอน TChatForm.ListenItemClick (ผู้ส่ง: TObject);
เริ่ม
ListenItem.Checked := ไม่ใช่ ListenItem.Checked;
ถ้า ListenItem.Checked แล้ว
เริ่ม
ClientSocket.Active := เท็จ;
ServerSocket.Active := จริง;
จบ
อื่น
เริ่ม
ถ้า ServerSocket.Active แล้ว
ServerSocket.Active := เท็จ;
จบ;
จบ;
คำอธิบายของเซ็กเมนต์ของโปรแกรมนี้มีดังนี้: เมื่อผู้ใช้เลือก ListemItem รายการ ListenItem จะถูกกลับด้าน หากเลือก แสดงว่าอยู่ในสถานะ Listen สิ่งที่ผู้อ่านต้องเข้าใจคือ Listen เป็นวิธีกรรมสิทธิ์เมื่อ Socket ให้บริการ เป็นเซิร์ฟเวอร์ หากอยู่ในสถานะ Listen แสดงว่า ServerSocket ถูกตั้งค่าเป็นสถานะใช้งานอยู่ มิฉะนั้น การฟังจะถูกยกเลิกและ ServerSocket จะถูกปิด ในความเป็นจริงมีเพียงผู้ใช้เท่านั้นที่เลือกรายการเมนูนี้ในตอนแรกซึ่งบ่งชี้ว่าโปรแกรมทำหน้าที่เป็นเซิร์ฟเวอร์ ในทางตรงกันข้าม หากผู้ใช้เลือก ConnectItem จะต้องใช้นั้นเป็นไคลเอ็นต์
3. ดับเบิลคลิก ConnectItem แล้วป้อนรหัสต่อไปนี้
ขั้นตอน TChatForm.ConnectItemClick (ผู้ส่ง: TObject);
เริ่ม
ถ้า ClientSocket.Active แล้วก็ ClientSocket.Active := False;
ถ้า InputQuery('คอมพิวเตอร์ที่จะเชื่อมต่อ', 'ชื่อที่อยู่:', เซิร์ฟเวอร์) แล้ว
ถ้าความยาว (เซิร์ฟเวอร์) > 0 แล้ว
ด้วย ClientSocket ทำ
เริ่ม
โฮสต์ := เซิร์ฟเวอร์;
ใช้งานอยู่ := จริง;
ListenItem.Checked := เท็จ;
จบ;
จบ;
หน้าที่หลักของโปรแกรมนี้คือการตั้งค่าแอปพลิเคชันเป็นไคลเอนต์เมื่อผู้ใช้เลือกรายการเมนู ConnectItem และกล่องอินพุตจะปรากฏขึ้นเพื่อให้ผู้ใช้สามารถป้อนที่อยู่ของเซิร์ฟเวอร์ได้ นี่คือเหตุผลที่เราไม่แก้ไขโฮสต์ ClientSocket ตั้งแต่เริ่มต้น เพื่อให้ผู้ใช้สามารถเชื่อมต่อกับเซิร์ฟเวอร์ที่แตกต่างกันแบบไดนามิกได้ สิ่งที่ผู้อ่านต้องเข้าใจก็คือที่อยู่โฮสต์เป็นเพียงคุณลักษณะที่ Socket มีเมื่อเป็นไคลเอนต์ เมื่อ Socket เป็นเซิร์ฟเวอร์ "โดยทั่วไป" จะไม่ใช้ที่อยู่เนื่องจากถูกผูกไว้กับเครื่องท้องถิ่น
4. เขียนรหัสต่อไปนี้ในวิธีการกดลงของ memo1:
ขั้นตอน TChatForm.Memo1KeyDown (ผู้ส่ง: TObject; คีย์ var: Word;
กะ: TShiftState);
เริ่ม
ถ้า Key = VK_Return แล้ว
ถ้า IsServer แล้ว
ServerSocket.Socket.Connections[0].SendText (Memo1.Lines[Memo1.Lines.Count - 1])
อื่น
ClientSocket.Socket.SendText(Memo1.Lines[Memo1.Lines.Count - 1]);
จบ;
ฟังก์ชั่นของโค้ดนี้ชัดเจนนั่นคือมันเริ่มส่งข้อความ หากเป็นเซิร์ฟเวอร์ ระบบจะส่งข้อความไปยังไคลเอนต์แรกเท่านั้น เนื่องจากเซิร์ฟเวอร์สามารถเชื่อมต่อกับไคลเอนต์ได้หลายตัว และการเชื่อมต่อกับไคลเอนต์แต่ละครั้งจะถูกดูแลโดยซ็อกเก็ต อาร์เรย์ ServerSocket.Socket.Connnections สิ่งที่ถูกเก็บไว้คือซ็อกเก็ต ที่รักษาการเชื่อมต่อกับลูกค้า ในซ็อกเก็ตมาตรฐาน ซ็อกเก็ตฝั่งเซิร์ฟเวอร์จะได้รับซ็อกเก็ตที่รักษาการเชื่อมต่อกับไคลเอนต์ผ่านค่าส่งคืนของเมธอด Accept() และวิธีการส่งและรับข้อความคือ send(sendto) และ recv(recvfrom) ตามลำดับ . Delphi ได้ทำ Encapsulation นี้แล้ว
5. การแนะนำสั้น ๆ เกี่ยวกับรหัสที่เหลือ
ขั้นตอน TChatForm.ServerSocketAccept (ผู้ส่ง: TObject;
ซ็อกเก็ต: TCustomWinSocket);
เริ่ม
IsServer := จริง;
จบ;
วิธีการยอมรับของ ServerSocket จะเสร็จสมบูรณ์เมื่อไคลเอนต์เชื่อมต่อเป็นครั้งแรก จากพารามิเตอร์ ถือว่าดำเนินการหลังจากวิธียอมรับมาตรฐาน เนื่องจากมีประเภทพารามิเตอร์ TCustomWinSocket จึงควรเป็นค่าที่ส่งคืนของ ซ็อกเก็ตฝั่งเซิร์ฟเวอร์มาตรฐาน
ขั้นตอน TChatForm.ClientSocketRead (ผู้ส่ง: TObject;
ซ็อกเก็ต: TCustomWinSocket);
เริ่ม
Memo2.Lines.Add(Socket.ReceiveText);
จบ;
ขั้นตอน TChatForm.ServerSocketClientRead (ผู้ส่ง: TObject;
ซ็อกเก็ต: TCustomWinSocket);
เริ่ม
Memo2.Lines.Add(Socket.ReceiveText);
จบ;
โค้ดสองชิ้นนี้ถูกเรียกใช้โดย Delphi เมื่อฝั่งเซิร์ฟเวอร์และฝั่งไคลเอ็นต์ได้รับข้อความของกันและกัน และหน้าที่ของโค้ดทั้งสองนี้คือการแสดงข้อความที่ได้รับใน memo2 ในหมู่พวกเขา Socket ใน ClientSocketRead จริงๆ แล้วคือ Socket เอง และ Socket ใน ServerSocketClientRead จริงๆ แล้วคือ Socket ใน ServerSocket.Socket.Connection[] อย่างไรก็ตาม ใน Delphi ซ็อกเก็ตฝั่งเซิร์ฟเวอร์ได้รับการห่อหุ้มอย่างมีประสิทธิภาพ
ขั้นตอน TChatForm.ServerSocketClientConnect (ผู้ส่ง: TObject;
ซ็อกเก็ต: TCustomWinSocket);
เริ่ม
Memo2.Lines.เคลียร์;
จบ;
ขั้นตอน TChatForm.ClientSocketDisconnect (ผู้ส่ง: TObject;
ซ็อกเก็ต: TCustomWinSocket);
เริ่ม
ListenItemClick(ไม่มี);
จบ;
สองย่อหน้านี้ค่อนข้างง่าย ServerSocketClientConnect จะถูกทริกเกอร์เมื่อ ServerSocket ได้รับการเชื่อมต่อใหม่ ClientSocketDisconnect ถูกทริกเกอร์เมื่อ ClientSocket ปัญหา Disconncet
ขั้นตอน TChatForm.Exit1Click (ผู้ส่ง: TObject);
เริ่ม
ServerSocket.ปิด;
ClientSocket.Close;
ปิด;
จบ;
ขั้นตอน TChatForm.Disconnect1Click (ผู้ส่ง: TObject);
เริ่ม
ClientSocket.Active := เท็จ;
ServerSocket.Active := จริง;
จบ;
ย่อหน้าแรกคือการปิดรับสมัคร ในซ็อกเก็ตมาตรฐาน เมื่อแต่ละซ็อกเก็ตถูกปิด จะต้องเรียกใช้เมธอด closesocket() มิฉะนั้นระบบจะไม่ปล่อยทรัพยากร ใน ServerSockt.Close และ ClientSocket.Close เมธอด closesocket() จะต้องถูกเรียกภายในระบบ
3. ซ็อกเก็ตมาตรฐานและซ็อกเก็ตใน Delphi
กรอบงานแอปพลิเคชันซ็อกเก็ตมาตรฐานมีดังนี้:
ฝั่งเซิร์ฟเวอร์: ซ็อกเก็ต()[สร้างซ็อกเก็ตใหม่]--ผูก()[ผูกด้วยที่อยู่เซิร์ฟเวอร์]--ฟัง()--ยอมรับ()--บล็อกรอ--อ่าน()[ยอมรับข้อความ ในหน้าต่าง แพลตฟอร์ม วิธีการส่ง (TCP) หรือ sendto (UDP)] - ประมวลผลคำขอบริการ - เขียน () [ส่งข้อความ ในแพลตฟอร์ม Windows วิธีการส่ง (TCP) หรือส่งไปที่(UDP)
ฝั่งไคลเอ็นต์นั้นค่อนข้างง่าย: Socket()--Connect() [เชื่อมต่อกับเซิร์ฟเวอร์เฉพาะผ่านพอร์ตที่แน่นอนซึ่งจะสร้างการเชื่อมต่อกับเซิร์ฟเวอร์]--Write()--Read()
ซ็อกเก็ตอาจใช้ TCP หรือ UDP และซ็อกเก็ตยังสร้างบนโปรโตคอลอื่นๆ เช่น IPX/SPX, DECNet เป็นต้น เมื่อสร้าง Socket ใหม่ คุณสามารถระบุประเภทของ Socket ที่จะสร้างได้ Bind() ใช้เพื่อผูกกับที่อยู่ของเซิร์ฟเวอร์ หากโฮสต์มีที่อยู่ IP เดียว บทบาทของการเชื่อมโยงนั้นค่อนข้างซ้ำซ้อน Listen() เริ่มตรวจสอบเครือข่าย Accept() ใช้เพื่อยอมรับการเชื่อมต่อ และค่าที่ส่งคืนคือ Socket ที่รักษาการติดต่อกับไคลเอนต์
ใน Delphi นั้น Socket ใน Windows ได้รับการห่อหุ้มอย่างมีประสิทธิภาพ ใน Delphi ตามความสัมพันธ์ทางมรดกสามารถแบ่งออกเป็นสองประเภท:
1. TComponent--TAbstractSocket--TCustomSocket--TCustomServerSocket--TServerSocket
TComponent - TAbstractSocket - TCustomSocket - TClientSocket
2. สืบทอดโดยตรงจาก TObject:
TObject - TCustomWinSocket - TServerWinSocket
TObject - TCustomWinSocket - TClientWinSocket
TObject - TCustomWinSocket - TServerClientWinSocket
จะเห็นได้ว่าประเภทแรกนั้นใช้ TCustomSocket และประเภทที่สองนั้นใช้ TCustomWinSocket ประเภทแรกสร้างขึ้นบน TComponet และประเภทที่สองสร้างขึ้นบน TObject โดยตรง ดังนั้นหากผู้ใช้คุ้นเคยกับ Socket เป็นอย่างดีและต้องการเขียนโปรแกรมคอนโซลเขาสามารถใช้คลาส TCustomWinScoket ได้
ดังที่เห็นได้จากการใช้งานแบบเดียวกัน ทั้งหมดนี้ถูกนำไปใช้ใน ScktComp.pas และ schtComp.pas มีไฟล์ winsock.pas หากคุณยังคงเจาะลึกไฟล์ winsock ต่อไป คุณจะพบวิธีการพื้นฐานทั้งหมดของ Windows Socket
ในความเป็นจริง หากคุณเข้าใจกรอบงานแอปพลิเคชัน Socket มาตรฐาน คุณจะสบายใจในการใช้ Delphi เพื่อเขียนแอปพลิเคชัน Socket แต่ไม่ได้หมายความว่าคุณต้องเข้าใจฟังก์ชันมาตรฐานใน Socket ที่ซับซ้อน และไม่จำเป็น เนื่องจาก Delphi ได้ทำไปแล้ว สำหรับคุณ มันถูกห่อหุ้มอย่างดีซึ่งเป็นจุดแข็งของ Delphi คุณเพียงแค่ต้องเข้าใจกรอบการทำงานพื้นฐานเพียงเล็กน้อยเท่านั้น
นี่คือความเข้าใจของฉันเกี่ยวกับแอปพลิเคชัน Socket ใน Delphi ฉันหวังว่าคุณจะสามารถแก้ไขฉันได้หากฉันมีข้อบกพร่อง ในเวลาเดียวกัน ฉันยินดีที่จะตอบคำถามเกี่ยวกับ Socket ใน Delphi