Delphi มีประสิทธิภาพมาก การเขียนซอฟต์แวร์ด้วย Delphi สามารถย่นระยะเวลาการพัฒนาซอฟต์แวร์ได้อย่างมาก แนวคิดพื้นฐานของการถ่ายโอนไฟล์แบบจุดต่อจุดคือซอฟต์แวร์เซิร์ฟเวอร์และซอฟต์แวร์ไคลเอนต์ใช้พอร์ตเดียวกัน หลังจากเชื่อมต่อแล้วไคลเอนต์จะส่งคำขอไปยังเซิร์ฟเวอร์รวมถึงชื่อไฟล์ขนาด ฯลฯ ไฟล์ที่จะโอน หากเซิร์ฟเวอร์ยอมรับและเริ่มถ่ายโอนไฟล์ แน่นอนว่ามีสองโหมดสำหรับการถ่ายโอนไฟล์ รหัส ASCII และ Bin แต่โดยทั่วไป Bin ก็เพียงพอแล้ว จากการสนทนาข้างต้น เดิมทีสามารถใช้ตัวควบคุม NMStrm และ NMStrmServ ของ Delphi4 ได้ อย่างไรก็ตาม ฉันได้ทดสอบแล้วและพบว่าตัวควบคุม NMStrm สามารถใช้กับไฟล์ขนาดเล็กได้และสะดวกมาก ) จะเกิดข้อผิดพลาดขึ้น ต่อไปเราจะใช้ TServerSocket และ TClientSocket ใน Delphi เพื่อเขียนโปรแกรมนี้ เนื่องจากข้อจำกัดของขนาดแพ็กเก็ต Ethernet และกลไกการประมวลผลของ DelphiSocket (ใน Delphi เมื่อคุณใช้ Socket เพื่อส่ง Stream ที่ใหญ่กว่า ผู้รับจะทริกเกอร์ OnRead หลายครั้ง . เหตุการณ์ Delphi รับประกันความสมบูรณ์ของแต่ละข้อมูลในเหตุการณ์ OnRead หลายเหตุการณ์เท่านั้น และไม่ได้รวบรวมข้อมูลเองและส่งคืนให้กับผู้ใช้ ดังนั้นอย่าคิดว่าคุณจะสามารถส่งไฟล์เพื่อถ่ายโอนได้ครั้งเดียวใน Socket และ Recv เดียว ในอีกทางหนึ่ง คุณต้องรวบรวมข้อมูลด้วยตัวเองหรือกำหนดโปรโตคอลด้วยตัวเอง) ดังนั้นเราจึงใช้วิธีโปรโตคอลที่กำหนดเอง วิธีมาตรฐานในการกำหนดโปรโตคอลคือการใช้การสิ้นสุดการบันทึก ชอบ:
TMyFilePRotocol=บันทึก
sSendType=(ST_QUERY,ST_REFUSE,ST_DATA,ST_ABORT,...);
ความยาว:จำนวนเต็ม;
bufSend:บัฟเฟอร์;
จบ;
ฉันได้ลองใช้วิธีนี้แล้ว แต่ล้มเหลว และฉันคิดเสมอว่าวิธีการของฉันถูกต้อง แต่โปรแกรมไม่สามารถคอมไพล์ได้เสมอ ฉันเดาว่ามีบางอย่างผิดปกติกับ Delphi :) ดังนั้นฉันจึงใช้วิธีอื่นในโปรแกรมตัวอย่างต่อไปนี้ มีคุณสมบัติสองประการคือ GetText และ ReceiverBuf ในคลาส Socket ในเหตุการณ์ OnRead คุณสมบัติทั้งสองนี้สามารถใช้ได้เพียงครั้งเดียว ดังนั้นเราจึงสามารถใช้ตัวแปรส่วนกลางเพื่อบันทึกว่าจะอ่าน Text หรือ Buf กล่าวคือ อ่าน ส่งข้อความหนึ่งครั้งแล้วอ่านอีกครั้ง Buf ซึ่งเป็นการจำลอง TMyFileProtocol
เริ่มโปรแกรม:
เขียนวิธีที่ง่ายที่สุด ใช้เพื่ออธิบายวิธีการเป็นหลัก
กำหนดโปรโตคอล:
คอนสตรัคชั่น
MP_QUERY ='1';
MP_REFUSE ='2';
MP_ACCEPT ='3';
MP_NEXTWILLBEDATA='4';
MP_DATA ='5';
MP_ABORT ='6';
MP_OVER ='7';
MP_CHAT ='8';
บทนำข้อตกลง:
ขั้นแรก ลูกค้าส่ง MP_QUERY และหลังจากได้รับแล้ว เซิร์ฟเวอร์จะส่ง MP_ACCEPT หรือ MP_FEFUESE
ลูกค้าส่ง MP_FILEPROPERTY หลังจากได้รับ MP_ACCEPT และเซิร์ฟเวอร์ส่ง MP_NEXTWILLBEDATA หลังจากได้รับแล้ว
ลูกค้าส่ง MP_NEXTWILLBEDATA หลังจากได้รับแล้ว และเซิร์ฟเวอร์ส่ง MP_DATA หลังจากได้รับแล้ว
ลูกค้าได้รับ MP_DATA และส่งข้อมูล เซิร์ฟเวอร์ได้รับข้อมูล และส่ง MP_NEXTWILLBEDATA
วนซ้ำจนกว่าไคลเอนต์จะส่ง MP_OVER;
MP_CHAT+String สามารถส่งหากันตรงกลางได้
โปรแกรมเซิร์ฟเวอร์:
วางตัวควบคุมต่อไปนี้:SaveDialog1,btnStartServer,
เอสเอส (TServerSocket)
btnStartServer.OnClick(ผู้ส่ง:TObject);
เริ่ม
เอสเอสพอร์ต:=2000;
เอสเอสเปิด;
จบ;
ss.OnClientRead (ผู้ส่ง: TObject; ซ็อกเก็ต: TCustomWinSocket);
var
sTemp:สตริง;
bufRecv:ตัวชี้;
iRecvLength: จำนวนเต็ม;
เริ่ม
ถ้า bReadText แล้ว
เริ่ม
sTemp:=Socket.ReceiveText;
กรณี sTemp[1] ของ
MP_QUERY:เริ่มต้น
//ปฏิเสธตรงนี้.
SaveDialog1.FileName:=คัดลอก(sTemp,2,ความยาว(STemp));
ถ้า SaveDialog1.Execute แล้ว
เริ่ม
ซ็อกเก็ต SendText (MP_ACCEPT);
fsRecv:=TFileStream.Create(SaveDialog1.FileName,fmCreate);
จบ
อื่น Socket.SendText (MP_REFUSE + 'ตาย');
จบ;
MP_FILEPROPERTY: เริ่มต้น
//หากต้องการส่ง StrToInt(Copy(sTemp,2,Length(sTemp))) ครั้ง
//แสดงความคืบหน้าของเวลา - -
ซ็อกเก็ต SendText (MP_NEXTWILLBEDATA);
จบ;
MP_NEXTWILLBEDATA:เริ่มต้น
ซ็อกเก็ต SendText (MP_DATA);
bReadText:=เท็จ;
จบ;
MP_END:เริ่มต้น
fsRecv.ฟรี
bReadText:=จริง;
จบ;
MP_ABORT:เริ่มต้น
fsRecv.ฟรี;
bReadText:=จริง;
จบ;
MP_CHAT:เริ่มต้น
//แชทข้อความ
จบ;
สิ้นสุด;{ของกรณี}
จบ
เริ่มอย่างอื่น
พยายาม
GetMem(bufRecv,2000);//2000 ต้อง >iBYTESEND
ซ็อกเก็ต.ReceiveBuf(bufRecv^,iRecvLength);
fsRecv.WriteBuffer(bufRecv^,iRecvLength);
ในที่สุด
FreeMem(bufRecv,2000);
สิ้นสุด;{ของความพยายาม}
bReadText:=จริง;
ซ็อกเก็ต SendText (MP_NEXTWILLBEDATA);
จบ;
จบ;
โปรแกรมไคลเอนต์:
วางตัวควบคุมต่อไปนี้: edtipAddress, OpenDialog1, btnConnect, btnSendFile,
cs (TClientSocket)
btnConnect.OnClick(ผู้ส่ง:TObject);
เริ่ม
cs.Address:=edtIPAddress.Text;
cs.พอร์ต:=2000;
cs.เชื่อมต่อ;
จบ;
btnSendFile.OnClick(ผู้ส่ง:TObject);
เริ่ม
ถ้า OpenDialog1.Execute แล้ว
เริ่ม
cs.Socket.SendText(MP_QUERY+OpenDialog1.FileName);//ขนาดไฟล์???
จบ;
จบ;
cs.OnRead (ผู้ส่ง: TObject; ซ็อกเก็ต: TCustomWinSocket);
var
sTemp:สตริง;
bufSend:ตัวชี้;
เริ่ม
sRecv:=Socket.ReceiveText;
กรณี sRecv[1] ของ
MP_REFUSE:ShowMessage('เป็นลม ถูกปฏิเสธ!');
MP_ACCEPT:เริ่มต้น
fsSend:=TFileStream.Create(OpenDialog1.FileName,fmOpen);
//iBYTEPERSEND เป็นค่าคงที่ ซึ่งเป็นขนาดของแพ็กเก็ตที่ส่งในแต่ละครั้ง
Socket.SendText(MP_FILEPROPERTY+Trunc(fsSend.Size/iBYTEPERSEND)+1);
จบ;
MP_NEXTWILLBEDATA:เริ่มต้น
ซ็อกเก็ต SendText (MP_NEXTWILLBEDATA);
จบ;
MP_DATA:เริ่มต้น
พยายาม
GetMem(bufSend,iBYTEPERSEND+1);
ถ้า (fsSend.Position+1+iBYTEPERSEND) < fsSend.Size แล้ว
เริ่ม
fsSend.Read(bufSend^,iBYTEPERSEND);
ซ็อกเก็ต SendBuf (bufSend ^, iBYTEPERSEND);
fsSend ฟรี;
end//ส่งธรรมดา ขนาด iBYTEPERSEND
เริ่มอย่างอื่น
fsSend.Read(bufSend^,fsSend.Size-fsSend.Position-1);
Socket.SendBuf(bufSend^,fsSend.Size-fsSend.ตำแหน่ง-1);
end;//ส่งครั้งสุดท้ายให้ส่งข้อมูลที่เหลือ
ในที่สุด
FreeMem(bufSend,iBYTEPERSEND+1);
สิ้นสุด;{ของความพยายาม}
จบ;
MP_ABORT:เริ่มต้น
//ยกเลิก :(
fsSend ฟรี;
จบ;
สิ้นสุด;{ของกรณี}
จบ;
ขั้นตอนการจัด:
เพิ่มการตัดสินข้อผิดพลาด, ปรับโปรแกรมให้เหมาะสม, รวมเซิร์ฟเวอร์และไคลเอนต์, เพิ่มการแสดงความคืบหน้าเวลาที่เหลือ, ทำให้สามารถถ่ายโอนไฟล์หลายไฟล์ในคราวเดียว, และเพิ่มฟังก์ชั่นแชทและกลายเป็นการถ่ายโอนไฟล์แบบจุดต่อจุดที่ดี โปรแกรม