我也曾经遇到过你这样的问题,现在已经解决(能完整发送像 Delphi7.rar 这样的大文件)。
由两个地方要注意的:
1.客户端发送完文件要 Disconnect
2.接受缓冲区最好和发送缓冲区一样大
这是我的一个能正常工作的:
unit uMain002;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, Forms,
Dialogs, StdCtrls, ScktComp, ComCtrls, IdGlobal, ExtCtrls;
type
TForm1 = class(TForm)
csClient: TClientSocket;
ssServer: TServerSocket;
gbState: TGroupBox;
pbSend: TProgressBar;
pbReceive: TProgressBar;
Label1: TLabel;
Label2: TLabel;
gbControl: TGroupBox;
btnSend: TButton;
btnChooseFile: TButton;
edtFileName: TEdit;
btnConnect: TButton;
Label3: TLabel;
edtServer: TEdit;
Label4: TLabel;
Bevel1: TBevel;
procedure btnSendClick(Sender: TObject);
procedure ssServerClientRead(Sender: TObject;
Socket: TCustomWinSocket);
procedure ssServerClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure btnChooseFileClick(Sender: TObject);
procedure btnConnectClick(Sender: TObject);
procedure csClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure csClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
procedure csClientRead(Sender: TObject; Socket: TCustomWinSocket);
procedure ssServerClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
private
procedure SendFile;
{ Private declarations }
public
{ Public declarations }
end;
TSendState = (ssCommand, ssSendingFile);
PSendRec = ^TSendRec;
TSendRec = packed record
FileName: String;
FileSize: Integer;
State: TSendState;
end;
const
B_SIZE = 32768;
RCV_SIZE = 32768;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.btnSendClick(Sender: TObject);
begin
pbSend.Max := FileSizeByName(edtFileName.Text);
csClient.Socket.SendText(Format('FILE@%s@%d', [edtFileName.Text, pbSend.Max]));
end;
procedure TForm1.SendFile;
var
fs: TFileStream;
buf: PByte;
snd: Integer;
begin
GetMem(buf, B_SIZE);
fs := TFileStream.Create(edtFileName.Text, fmOpenRead);
fs.Position := 0;
try
pbSend.Max := fs.Size;
{ 发送数据 }
repeat
snd := fs.Read(buf^, B_SIZE);
csClient.Socket.SendBuf(buf^, snd);
pbSend.Position := pbSend.Position + snd;
Application.ProcessMessages;
until snd <= 0;
csClient.Active := False; // 必须,否则会丢失数据
finally
FreeMem(buf);
fs.Free;
end;
ShowMessage('文件发送完毕');
end;
procedure TForm1.ssServerClientRead(Sender: TObject;
Socket: TCustomWinSocket);
var
fs: TFileStream;
buf: PByte;
rcv: Integer;
strTemp: String;
fmode: Word;
{ 从接收到的信息取出文件名 }
function GetSaveFileName(fn: String): String;
begin
with TSaveDialog.Create(nil) do
try
Result := Copy(fn, 1, Pos('@', fn) - 1);
FileName := Result;
InitialDir := GetCurrentDir;
if Execute then Result := FileName;
finally
Free;
end;
end;
begin
if PSendRec(Socket.Data).State = ssCommand then
begin
{ 从接收到的数据中获取 文件长度、文件名信息 }
strTemp := Socket.ReceiveText;
if Pos('FILE', strTemp) <> 1 then Exit;
Delete(strTemp, 1, Pos('@', strTemp));
PSendRec(Socket.Data).FileName := GetSaveFileName(strTemp);
Delete(strTemp, 1, Pos('@', strTemp));
PSendRec(Socket.Data).FileSize := StrToInt(strTemp);
PSendRec(Socket.Data).State := ssSendingFile;
pbReceive.Max := PSendRec(Socket.Data).FileSize;
Socket.SendText('Send file OK');
end
else begin
{ 第一次接收到文件数据时,创建文件,以后打开文件往里面写数据 }
if FileExists(PSendRec(Socket.Data).FileName) then
fmode := fmOpenWrite
else fmode := fmCreate;
fs := TFileStream.Create(PSendRec(Socket.Data).FileName, fmode);
fs.Seek(0, soFromEnd);
GetMem(buf, RCV_SIZE);
{ 接收数据并写入文件 }
try
repeat
rcv := Socket.ReceiveBuf(buf^, RCV_SIZE);
fs.Write(buf^, rcv);
pbReceive.Position := pbReceive.Position + rcv;
until rcv <= 0;
finally
FreeMem(buf);
fs.Free;
end;
end;
end;
procedure TForm1.ssServerClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
var
rec: PSendRec;
begin
New(rec);
rec^.State := ssCommand;
Socket.Data := rec;
end;
function GetFileName: String;
begin
with TOpenDialog.Create(nil) do
try
if Execute then Result := FileName;
finally
Free;
end;
end;
procedure TForm1.btnChooseFileClick(Sender: TObject);
begin
edtFileName.Text := GetFileName;
end;
procedure TForm1.btnConnectClick(Sender: TObject);
begin
csClient.Port := 4545;
csClient.Address := edtServer.Text;
csClient.Active := True;
end;
procedure TForm1.csClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
btnSend.Enabled := True;
end;
procedure TForm1.csClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
btnSend.Enabled := False;
end;
procedure TForm1.csClientRead(Sender: TObject;
Socket: TCustomWinSocket);
begin
if Socket.ReceiveText = 'Send file OK' then
SendFile;
end;
procedure TForm1.ssServerClientDisconnect(Sender: TObject;
Socket: TCustomWinSocket);
begin
Dispose(PSendRec(Socket.Data));
ShowMessage('文件接收完毕');
end;
end.