[บทคัดย่อ] โปรแกรมเมอร์ที่เขียนแอปพลิเคชัน Winsock รู้ดีว่าการเขียนแอปพลิเคชัน Winsock นั้นไม่ใช่เรื่องง่าย คุณต้องไม่จัดการกับ API ที่ซับซ้อนใน Winsock โดยตรง โชคดีที่ Tclientsocket และ Tserversocket ใน Delphi4 ห่อหุ้ม API ที่เกี่ยวข้องใน Windows ทำให้การเข้าถึงง่ายขึ้นอย่างมาก สู่ Winsock ทำให้เราสามารถเขียนแอปพลิเคชัน Winsock ได้อย่างง่ายดาย บทความนี้จะแนะนำวิธีเขียนแอปพลิเคชัน Winsock โดยใช้ Delphi ผ่านตัวอย่างการอ่านหน้าจอของคอมพิวเตอร์เครื่องอื่นใน LAN
ใครก็ตามที่เคยทำงานเป็นผู้ดูแลระบบเครือข่ายในที่ทำงานอาจเคยมีประสบการณ์เช่นนี้มาก่อน การสั่งให้ผู้อื่นสั่งงานผ่าน "รีโมทคอนโทรล" ทางโทรศัพท์ ยิ่งกว่านั้น ฉันเป็นคนขี้เกียจและไม่อยากวิ่งหนี ชั้นบนถึงชั้นล่างมีเรื่องเล็กๆ น้อยๆ ทุกวัน จะทำอย่างไร? แล้วการเขียนโปรแกรมที่อ่านหน้าจอคอมพิวเตอร์เครื่องอื่นล่ะ? มันใช้งานง่ายกว่ามาก ในการสื่อสารภายใน LAN ทางเลือกที่ดีที่สุดคือการใช้ Winsock โปรแกรมเมอร์ที่เขียนแอปพลิเคชัน Winsock รู้ว่าการเขียนแอปพลิเคชัน Winsock นั้นไม่ใช่เรื่องง่าย คุณต้องไม่จัดการกับ API ที่ซับซ้อนใน Winsock โดยตรง และ Tserversocket ใน Delphi4 ห่อหุ้ม API ที่เกี่ยวข้องใน Windows ซึ่งช่วยให้เข้าถึง Winsock ได้ง่ายขึ้นอย่างมาก และช่วยให้เราเขียนแอปพลิเคชัน Winsock ได้อย่างง่ายดาย อย่างไรก็ตาม เป็นการดีที่สุดที่จะมีความเข้าใจเกี่ยวกับ Winsock ฉันจะไม่ลงรายละเอียดที่นี่ คุณสามารถหาหนังสือและอ่านเองได้
ในการส่งข้อมูลผ่านเครือข่าย คุณต้องมีซ็อกเก็ตอย่างน้อยหนึ่งคู่ บนไคลเอนต์และอีกอันบนเซิร์ฟเวอร์ เมื่อไคลเอนต์และซ็อกเก็ตของเซิร์ฟเวอร์สร้างการเชื่อมต่อแล้ว ทั้งสองก็สามารถสื่อสารระหว่างกันได้ ก่อตั้งขึ้นบน Tcp/ ตาม ip นอกจากนี้ยังรองรับ ipx/spx และโปรโตคอลอื่นๆ ที่เกี่ยวข้อง ใน Delphi นั้น Tclientsocket และ Tserversocket ใช้เพื่อควบคุมการเชื่อมต่อและการสื่อสารระหว่างไคลเอนต์และซ็อกเก็ตเซิร์ฟเวอร์ ควรสังเกตว่าองค์ประกอบทั้งสองนี้ใช้เพื่อจัดการการเชื่อมต่อระหว่างเซิร์ฟเวอร์และไคลเอนต์ ไม่ใช่วัตถุ Socket เอง TcustomwinSocket เช่น Tclientwinsocket, Tserverclientwinsocket และ Tserverwinsocket
1. ส่วนประกอบ Tclientsocket:
ด้วยการเพิ่ม Tclientsocket ลงในแบบฟอร์ม แอปพลิเคชันจะกลายเป็นไคลเอ็นต์ Tcp/ip และ Tclientsocket สามารถใช้เพื่อจัดการอ็อบเจ็กต์ Socket ของไคลเอ็นต์ได้
หากต้องการสร้างการเชื่อมต่อกับเซิร์ฟเวอร์ คุณต้องระบุเซิร์ฟเวอร์ที่คุณต้องการเชื่อมต่อก่อน การระบุเซิร์ฟเวอร์ทำได้ 2 วิธี วิธีหนึ่งคือการตั้งค่าแอตทริบิวต์ Host ให้ระบุชื่อโฮสต์ของเซิร์ฟเวอร์ เช่น http://www.inPRise.com หรือชื่อเครื่องใน LAN วิธีการนี้ทำได้ง่ายมาก ต้องใช้การแก้ไขชื่อโดเมนซึ่งจะเร็วขึ้นเล็กน้อย อีกวิธีคือ ตั้งค่าแอตทริบิวต์ Adress ให้ระบุที่อยู่ IP ของโฮสต์ เช่น 130.0.1.1 ทั้งสองวิธีเทียบเท่ากัน แต่หากมีการตั้งค่าทั้งโฮสต์และที่อยู่ Delphi จะใช้คุณสมบัติโฮสต์เท่านั้น
จากนั้นคุณต้องระบุหมายเลขพอร์ตเพื่อเชื่อมต่อกับเซิร์ฟเวอร์ มีสองวิธีที่นี่ วิธีแรกคือการตั้งค่าบริการให้ใช้หมายเลขพอร์ตเริ่มต้น ได้รับการจัดสรรจำนวนมากเช่น FTP พอร์ตคือ 20 และ 21 พอร์ต SMTP คือ 25 พอร์ตเซิร์ฟเวอร์ WEB คือ 80 เป็นต้น เพื่อป้องกันความขัดแย้งโดยไม่ได้ตั้งใจขอแนะนำให้เมื่อเขียนโปรแกรมแอปพลิเคชันของคุณเอง ทางที่ดีควรตั้งค่าพอร์ตเป็น 1024 หรือสูงกว่า หากตั้งค่าบริการและพอร์ตพร้อมกัน Delphi จะใช้พอร์ตเริ่มต้นของบริการ
หลังจากระบุเซิร์ฟเวอร์และหมายเลขพอร์ตแล้ว ให้เรียกวิธีการเปิดหรือตั้งค่าแอตทริบิวต์ Active เป็น True ซ็อกเก็ตของไคลเอ็นต์จะทำการร้องขอการเชื่อมต่อกับซ็อกเก็ตของเซิร์ฟเวอร์ หากเซิร์ฟเวอร์อยู่ในสถานะการฟังในขณะนี้ เซิร์ฟเวอร์จะยอมรับโดยอัตโนมัติ ขอสร้างการเชื่อมต่อ เมื่อเชื่อมต่อแล้ว เหตุการณ์ Onconnet จะถูกทริกเกอร์ เมื่อคุณต้องการยกเลิกการเชื่อมต่อ คุณเพียงแค่ต้องเรียกเมธอด close หรือตั้งค่าแอตทริบิวต์ Active เป็น False ในขณะนี้ เหตุการณ์ ondisconnet จะถูกทริกเกอร์
2. ส่วนประกอบเซิร์ฟเวอร์ซ็อกเก็ต:
เช่นเดียวกับ Tclientsocket ในการสร้างเซิร์ฟเวอร์ คุณจะต้องวางส่วนประกอบ Tserversock ในแบบฟอร์มเท่านั้น
วัตถุซ็อกเก็ตฝั่งเซิร์ฟเวอร์มีความซับซ้อนในการจัดการ เมื่อเซิร์ฟเวอร์อยู่ในสถานะการฟัง ซ็อกเก็ตออบเจ็กต์ของเซิร์ฟเวอร์จะถูกจัดการโดย Tserversocket เมื่อไคลเอ็นต์ทำการร้องขอ เซิร์ฟเวอร์จะตอบสนองต่อคำขอและสร้างการเชื่อมต่อ ในเวลานี้ Tserverclientwinsocket จะถูกใช้เพื่อจัดการการเชื่อมต่อระหว่างเซิร์ฟเวอร์ ซ็อกเก็ตและซ็อกเก็ตของลูกค้า
หากต้องการให้เซิร์ฟเวอร์อยู่ในสถานะการฟัง คุณต้องระบุหมายเลขพอร์ตก่อน แน่นอนว่าควรเป็นหมายเลขเดียวกับหมายเลขพอร์ตของไคลเอ็นต์ จากนั้นเรียกเมธอด open หรือตั้งค่าคุณสมบัติ Active เป็น True
3. การสื่อสาร:
เมื่อสร้างการเชื่อมต่อระหว่างไคลเอนต์และเซิร์ฟเวอร์แล้ว การสื่อสารระหว่างกันก็สามารถเริ่มต้นได้ Delphi มีวิธีการสื่อสารหลายวิธีสำหรับ Tserversocket และ Tclientsocket Sendtext ใช้เพื่อส่งข้อมูลข้อความ sendstream ใช้เพื่อส่งสตรีม และ SendBuf ใช้เพื่อส่งข้อมูลตามความยาวที่ระบุ
ควรสังเกตว่าเนื่องจากขนาดบัฟเฟอร์เริ่มต้นของ Windows คือ 4K เมื่อส่งข้อมูลที่ยาวกว่า 4K เช่น สตรีมไบนารีที่ส่งจากเซิร์ฟเวอร์ไปยังไคลเอนต์ คุณจะต้องใช้ Socket.SendStream() บนเซิร์ฟเวอร์เท่านั้น แต่จะแตกต่างกันในไคลเอนต์ มันจะทริกเกอร์เหตุการณ์ onread หลายครั้งและ Delphi ไม่ได้กำหนดเหตุการณ์เช่น "onreadend" ดังนั้นโปรแกรมเมอร์จะต้องรวบรวมข้อมูลด้วยตนเองเมื่อได้รับ วิธีการที่ใช้ในบทความนี้คือส่งความยาวสตรีมไปยังไคลเอนต์ก่อน จากนั้นจึงส่งสตรีมข้อมูลที่ได้รับลงในสตรีม เมื่อความยาวสตรีมเท่ากับความยาวที่เซิร์ฟเวอร์ส่งกลับ ที่ลูกค้าได้รับเรียบร้อยแล้ว สำหรับเซิร์ฟเวอร์ สตรีมที่ใช้เป็นพารามิเตอร์ sendstream จะเป็น "เจ้าของ" โดยซ็อกเก็ต เมื่อออบเจ็กต์ Socket สิ้นสุดลง สตรีมนั้นจะสิ้นสุดเช่นกัน มิฉะนั้น ข้อยกเว้นจะถูกทริกเกอร์
ในทำนองเดียวกันเมื่อข้อความที่ส่งน้อยกว่า 4K เช่นเมื่อทำการเรียกต่อไปนี้ในโปรแกรมไคลเอนต์
clientocket1.Socket.SendText('ได้รับ');
clientocket1.Socket.SendText('ได้รับ');
clientocket1.Socket.SendText('ได้รับ');
เมื่อเซิร์ฟเวอร์ได้รับ ปรากฏการณ์ต่างๆ เช่น getsgets จะปรากฏขึ้น อาจเป็นเพราะเมื่อข้อมูลในบัฟเฟอร์ยังไม่ได้ถูกส่ง ข้อความใหม่จะถูกใส่ลงในบัฟเฟอร์ และคอมพิวเตอร์จะถือว่าข้อมูลดังกล่าวเป็นชุดข้อมูลเดียวกันสำหรับการประมวลผล . เพื่อหลีกเลี่ยงไม่ให้ปรากฏการณ์นี้เกิดขึ้น คุณสามารถใช้วิธี "ขว้างลูกบอล" ไปมาในโปรแกรมได้:
เซิร์ฟเวอร์ไคลเอนต์
clientocket1.Socket.SendText ('data1') socket.ReceiveText;
socket.sendtext('ตกลง');
ซ็อกเก็ต.รับข้อความ;
clientocket1.Socket.SendText ('data2')
ซ็อกเก็ต.ReceiveText;
socket.sendtext('สิ้นสุด');
ซ็อกเก็ต.รับข้อความ;
หลังจากรันโปรแกรมเซิร์ฟเวอร์บนคอมพิวเตอร์เครื่องอื่นแล้ว ให้ป้อนชื่อคอมพิวเตอร์ในกล่องข้อความบนโปรแกรมไคลเอนต์ของคุณ คลิก "เชื่อมต่อ" และคลิก "รับรูปภาพ" คุณจะมองเห็นหน้าจอคอมพิวเตอร์ของอีกฝ่ายได้อย่างชัดเจน ต่อไปนี้เป็นซอร์สโค้ดทั้งหมดของโปรแกรม โปรแกรมนี้สามารถทำงานใน NT4.0, Win95, Win98 และ LAN แน่นอนว่า Windows ต้องมีการติดตั้งโปรโตคอล TCP/IP และต้องมี IP ที่กำหนดหรือระบุแบบไดนามิก ที่อยู่.
หากคุณพบว่าการ "สั่งการ" ขณะรับชมเป็นเรื่องยาก คุณยังสามารถวิเคราะห์เหตุการณ์ของแป้นพิมพ์และเมาส์บน image1 แล้วส่งไปยังเซิร์ฟเวอร์ได้ หลังจากที่เซิร์ฟเวอร์ได้รับเหตุการณ์ดังกล่าว มันก็จะดำเนินการแบบเดิมอีกครั้ง ดังนั้นคุณจึงไม่ต้องดำเนินการ ผู้ประกอบการไม่ต้องกังวล การใช้ Tclientsocket และ Tserversocket ของ Delphi ช่วยให้คุณสามารถพัฒนาแอปพลิเคชันต่างๆ เช่น การคัดลอกไฟล์ การแชทออนไลน์ ICQ ฯลฯ ได้อย่างง่ายดาย คุณสามารถใช้จินตนาการของคุณได้อย่างอิสระเพื่อเขียนโปรแกรมที่น่าสนใจยิ่งขึ้น
โปรแกรมไคลเอนต์:
หน่วยคงอยู่;
อินเตอร์เฟซ
การใช้งาน
Windows, ข้อความ, SysUtils, คลาส, กราฟิก, การควบคุม, แบบฟอร์ม, กล่องโต้ตอบ,
ScktComp, StdCtrls, ExtCtrls, jpeg;
พิมพ์
TForm1 = คลาส (TForm)
แผง 1: TPanel;
ScrollBox1: TScrollBox;
ภาพที่ 1: TImage;
Button1: T ปุ่ม;
แก้ไข 1: TEdit;
Button2: T ปุ่ม;
ClientSocket1: TClientSocket;
Label1: TLabel;
ขั้นตอน Button1Click (ผู้ส่ง: TObject);
ขั้นตอน Button2Click (ผู้ส่ง: TObject);
ขั้นตอน ClientSocket1Connect (ผู้ส่ง: TObject;
ซ็อกเก็ต: TCustomWinSocket);
ขั้นตอน ClientSocket1Error (ผู้ส่ง: TObject; ซ็อกเก็ต: TCustomWinSocket;
ErrorEvent: TERrorEvent; var ErrorCode: จำนวนเต็ม);
ขั้นตอน ClientSocket1Read (ผู้ส่ง: TObject; ซ็อกเก็ต: TCustomWinSocket);
ขั้นตอน FormCreate (ผู้ส่ง: TObject);
ขั้นตอน FormClose (ผู้ส่ง: TObject; var Action: TCloseAction);
ส่วนตัว
{ประกาศส่วนตัว}
สาธารณะ
{ประกาศสาธารณะ}
จบ;
var
แบบฟอร์ม 1: TForm1;
c:ลองจินต์;
m:tmemorystream;
การดำเนินการ
{$R *.DFM}
ขั้นตอน TForm1.Button1Click (ผู้ส่ง: TObject);
เริ่ม
พยายาม
ลูกค้าซ็อกเก็ต1.ปิด;
clientocket1.Host:=edit1.text;
clientocket1.Open; //เชื่อมต่อกับเซิร์ฟเวอร์
ยกเว้น
showmessage(edit1.text+#13#10+'คอมพิวเตอร์ไม่ได้เปิดอยู่หรือไม่ได้ติดตั้งเซอร์วิสโปรแกรม');
จบ;
จบ;
ขั้นตอน TForm1.Button2Click (ผู้ส่ง: TObject);
เริ่ม
clientocket1.Socket.SendText('gets'); //ส่งคำขอเพื่อแจ้งเซิร์ฟเวอร์ว่าจำเป็นต้องมีภาพหน้าจอ
จบ;
ขั้นตอน TForm1.ClientSocket1Connect (ผู้ส่ง: TObject;
ซ็อกเก็ต: TCustomWinSocket);
เริ่ม
Caption:='เชื่อมต่อกับ'+edit1.text;
จบ;
ขั้นตอน TForm1.ClientSocket1Error (ผู้ส่ง: TObject;
ซ็อกเก็ต: TCustomWinSocket; ErrorEvent: TERrorEvent;
varErrorCode: จำนวนเต็ม);
เริ่ม
Caption:='Connection'+edit1.text+'Failed';
showmessage(edit1.text+#13#10+'คอมพิวเตอร์ไม่ได้เปิดอยู่หรือไม่ได้ติดตั้งเซอร์วิสโปรแกรม');
รหัสข้อผิดพลาด:=0;
จบ;
ขั้นตอน TForm1.ClientSocket1Read (ผู้ส่ง: TObject;
ซ็อกเก็ต: TCustomWinSocket);
var
buffer:array [0..10000] ของไบต์; //ตั้งค่าบัฟเฟอร์การรับ
เลน: จำนวนเต็ม;
จะ:สตริง;
ข:บิตแมป;
เจ: tjpeg ภาพ;
เริ่ม
ถ้า c=0 ดังนั้น //C คือจำนวนไบต์ที่เซิร์ฟเวอร์ส่ง ถ้าเป็น 0 แสดงว่าการรับภาพยังไม่เริ่มต้น
เริ่ม
ll:=socket.ReceiveText;
c:=strtoint(ll); //กำหนดจำนวนไบต์ที่จะรับ
clientocket1.Socket.SendText('okok'); //แจ้งให้เซิร์ฟเวอร์เริ่มส่งรูปภาพ
จบอย่างอื่น
start //ต่อไปนี้เป็นส่วนรับข้อมูลรูปภาพ
len:=socket.ReceiveLength; //อ่านความยาวของแพ็กเก็ต
socket.ReceiveBuf(buffer,len); //รับแพ็กเก็ตข้อมูลและอ่านลงในบัฟเฟอร์
m.Write(buffer,len); //ผนวกเข้ากับสตรีม M
ถ้า m.Size>=c ดังนั้น //หากความยาวสตรีมมากกว่าจำนวนไบต์ที่จะรับ แสดงว่าการรับเสร็จสมบูรณ์
เริ่ม
ม.ตำแหน่ง:=0;
b:=tbitmap.สร้าง;
j:=tjpegimage.Create;
พยายาม
j.LoadFromStream(m); //อ่านข้อมูลในสตรีม M ลงในวัตถุรูปภาพ JPG
b.Assign(j); // แปลง JPG เป็น BMP
Image1.Picture.Bitmap.Assign (b); // กำหนดให้กับองค์ประกอบ image1
ในที่สุด //ต่อไปนี้เป็นงานล้างข้อมูล
ข.ฟรี;
เจฟรี;
ลูกค้าซ็อกเก็ต1.ใช้งานอยู่:=เท็จ;
ลูกค้าซ็อกเก็ต1.ใช้งานอยู่:=จริง;
ม.เคลียร์;
ค:=0;
จบ;
จบ;
จบ;
จบ;
ขั้นตอน TForm1.FormCreate (ผู้ส่ง: TObject);
เริ่ม
m:=tmemorystream.Create;
จบ;
ขั้นตอน TForm1.FormClose (ผู้ส่ง: TObject; var Action: TCloseAction);
เริ่ม
ม.ฟรี;
ClientSocket1.ปิด;
จบ;
จบ.
โปรแกรมเซิร์ฟเวอร์:
ยูนิตที่เหลืออยู่
อินเตอร์เฟซ
การใช้งาน
Windows, ข้อความ, SysUtils, คลาส, กราฟิก, การควบคุม, แบบฟอร์ม, กล่องโต้ตอบ,
SccktComp, jpeg;
พิมพ์
TForm1 = คลาส (TForm)
ServerSocket1: TServerSocket;
ขั้นตอน ServerSocket1ClientRead (ผู้ส่ง: TObject;
ซ็อกเก็ต: TCustomWinSocket);
ขั้นตอน FormCreate (ผู้ส่ง: TObject);
ส่วนตัว
{ประกาศส่วนตัว}
สาธารณะ
{ประกาศสาธารณะ}
จบ;
var
แบบฟอร์ม 1: TForm1;
m1:tmemorystream;
การดำเนินการ
{$R *.DFM}
ขั้นตอน TForm1.ServerSocket1ClientRead (ผู้ส่ง: TObject;
ซ็อกเก็ต: TCustomWinSocket);
var
s,s1:สตริง;
โต๊ะ:tcanvas;
บิตแมป:tbitmap;
jpg:tjpegimage;
เริ่ม
s:=socket.ReceiveText;
ถ้า s='gets' ดังนั้น // ลูกค้าจะออกคำขอ
เริ่ม
บิตแมป:=tbitmap.Create;
jpg:=tjpegimage.สร้าง;
โต๊ะ:=tcanvas.Create; //รหัสต่อไปนี้คือการรับภาพหน้าจอปัจจุบัน
โต๊ะ.Handle:=getdc(hwnd_desktop);
m1:=tmemorystream.Create; //เตรียมใช้งานสตรีม m1 หลังจากส่งสตรีมด้วย sendstream(m1)
//มันจะยังคงอยู่จนกว่าการสนทนาซ็อกเก็ตจะสิ้นสุดลง
//ไม่สามารถปล่อยด้วยตนเองได้ ไม่เช่นนั้นจะเกิดข้อยกเว้นขึ้น
ด้วยบิตแมปทำ
เริ่ม
ความกว้าง:=หน้าจอความกว้าง;
ความสูง:=หน้าจอความสูง;
canvas.CopyRect(canvas.cliprect,โต๊ะ,desk.cliprect);
จบ;
jpg.Assign(bitmap); //แปลงรูปภาพเป็นรูปแบบ JPG
jpg.SaveToStream(m1); //เขียนภาพ JPG ลงในสตรีม
jpg.ฟรี;
m1.ตำแหน่ง:=0;
s1:=inttostr(m1.size);
Socket.sendtext(s1); //ส่งขนาดรูปภาพ
จบ;
ถ้า s='okok' ดังนั้น // ลูกค้าก็พร้อมที่จะรับภาพ
เริ่ม
m1.ตำแหน่ง:=0;
Socket.SendStream(m1); //ส่งภาพ JPG
จบ;
จบ;
ขั้นตอน TForm1.FormCreate (ผู้ส่ง: TObject);
เริ่ม
ServerSocket1.open;
จบ;
จบ.