Article summary:
Delphi is powerful. Writing software with Delphi can greatly shorten the software development cycle. This article introduces how to use Delphi to write a point-to-point file transfer program.
--------------------------------------------------
Delphi is powerful. Writing software with Delphi can greatly shorten the software development cycle. The basic idea of point-to-point file transfer is that a server software and a client software use the same port. After being connected, the client sends a request to the server, including the file name, size, etc. of the file to be transferred. If the server Accept and start transferring files. Of course, there are two modes for file transfer, ASCII code and Bin, but generally Bin is sufficient. Based on the above discussion, it was originally possible to use Delphi4's NMStrm and NMStrmServ controls. However, I have tested it and found that the NMStrm control can be used for smaller files and is very convenient. However, if the file is large (1M), an error will occur. So next we use TServerSocket and TClientSocket in Delphi to write this program. Due to the limitation of Ethernet packet size and the processing mechanism of DelphiSocket (in Delphi, when you use a Socket to send a larger Stream, the receiver will trigger OnRead multiple times. event, Delphi only guarantees the integrity of each data in multiple OnRead events, and does not collect the data itself and return it to the user, so don't think that you can send the file to be transferred once in one Socket and Recv once in another. . You have to collect the data yourself or define the protocol yourself), so we adopt the custom protocol method. The canonical way to define a protocol is to use Record End. like:
TMyFilePRotocol=Record
sSendType=(ST_QUERY,ST_REFUSE,ST_DATA,ST_ABORT,...);
iLength:integer;
bufSend:Buffer;
End;
I have tried this method, but it failed, and I always thought that my method was correct, but the program always failed to compile. I guess there was something wrong with Delphi:) So I used another method in the following sample program. There are two properties, ReceiveText and ReceiveBuf, in the Socket class. In an OnRead event, these two properties can only be used once, so we can use a global variable to save whether to read Text or Buf, that is to say, read Text once and read it again. Buf, this simulates TMyFileProtocol.
Start the program:
Write the simplest one, mainly used to explain the method.
Define protocol:
Const
MP_QUERY ='1';
MP_REFUSE ='2';
MP_ACCEPT ='3';
MP_NEXTWILLBEDATA='4';
MP_DATA ='5';
MP_ABORT ='6';
MP_OVER ='7';
MP_CHAT ='8';
Agreement introduction:
First, the Client sends MP_QUERY, and after receiving it, the Server sends MP_ACCEPT or MP_FEFUESE;
The Client sends MP_FILEPROPERTY after receiving MP_ACCEPT, and the Server sends MP_NEXTWILLBEDATA after receiving it;
The Client sends MP_NEXTWILLBEDATA after receiving it, and the Server sends MP_DATA after receiving it;
Client receives MP_DATA and sends data, Server receives data and sends MP_NEXTWILLBEDATA;
Loop until Client sends MP_OVER;
MP_CHAT+String can be sent to each other in the middle;
Server program:
Place the following controls:SaveDialog1,btnStartServer,
ss,(TServerSocket)
btnStartServer.OnClick(Sender:TObject);
begin
ss.Port:=2000;
ss.Open;
end;
ss.OnClientRead(Sender: TObject;Socket: TCustomWinSocket);
var
sTemp:string;
bufRecv:Pointer;
iRecvLength:integer;
begin
if bReadText then
begin
sTemp:=Socket.ReceiveText;
case sTemp[1] of
MP_QUERY:begin
//Reject here
SaveDialog1.FileName:=Copy(sTemp,2,Length(STemp));
if SaveDialog1.Execute then
begin
Socket.SendText(MP_ACCEPT);
fsRecv:=TFileStream.Create(SaveDialog1.FileName,fmCreate);
end
else Socket.SendText(MP_REFUSE+'die');
end;
MP_FILEPROPERTY:begin
//To send StrToInt(Copy(sTemp,2,Length(sTemp))) times
//Time progress display. . .
Socket.SendText(MP_NEXTWILLBEDATA);
end;
MP_NEXTWILLBEDATA:begin
Socket.SendText(MP_DATA);
bReadText:=false;
end;
MP_END:begin
fsRecv.Free
bReadText:=true;
end;
MP_ABORT:begin
fsRecv.Free;
bReadText:=true;
end;
MP_CHAT:begin
//Chat Msg
end;
end;{of case}
end
else begin
try
GetMem(bufRecv,2000);//2000 must >iBYTESEND
Socket.ReceiveBuf(bufRecv^,iRecvLength);
fsRecv.WriteBuffer(bufRecv^,iRecvLength);
finally
FreeMem(bufRecv,2000);
end;{of try}
bReadText:=true;
Socket.SendText(MP_NEXTWILLBEDATA);
end;
end;
Client program:
Place the following controls: edtipAddress, OpenDialog1, btnConnect, btnSendFile,
cs. (TClientSocket)
btnConnect.OnClick(Sender:TObject);
begin
cs.Address:=edtIPAddress.Text;
cs.Port:=2000;
cs.Connect;
end;
btnSendFile.OnClick(Sender:TObject);
begin
if OpenDialog1.Execute then
Begin
cs.Socket.SendText(MP_QUERY+OpenDialog1.FileName);//FileSize???