客户端向服务端发送zip文件包,由于文件比较大,客户有很多个,我采用异步连接方式,客户端先发送固定大小的字节,因为sock可能自动分包,我服务端循环读取,直到读取的字节为-1,再给客户端信息,客户端再发送,服务端再接收。本来程序做好了,再我的本机上测试也没有问题,我也向我们的老板吹牛,没有什么问题了,可是我用两台机器测试,发觉如果每次发送的包为1024字节,程序没有问题,接收的文件很正常,但我觉得发送太慢,于是改为每次发送8192或4096,这是测试,程序到没有问题,可是接收的Zip文件中的图像有一小部分的已经损坏,这下我心里凉了,今天下午就要去客户那里测试了啊,大哥们,帮忙说说为什么吧?部分程序如下:
client//准备文件流
PRFS_SendFile := TFileStream.Create(Pb_ZipPath+trim(ls_BatchName)+'.Zip', fmOpenRead or fmShareDenyNone);
//发送文件名与长度
PPFM_Send.FileName :=ls_BatchName;
PPFM_Send.Size := PRi_LostSize ;
CSK_Send.Socket.SendBuf(PPFM_Send^,Sizeof(PPFM_Send^));
procedure TFrm_Client.CSK_SendRead(Sender: TObject;
Socket: TCustomWinSocket);
beginif PRSP_Protocol.Protocol = 'Y' then //服务端已准备好
begin if PRi_LostSize > 1024 then //如果剩下的文件大小大于4000,
li_ESendSize := 1024
else
li_ESendSize := PRi_LostSize; try
PRFS_SendFile.ReadBuffer(SendBuf^, li_ESendSize);
Socket.SendBuf(SendBuf^, li_ESendSize);
except
On E:Exception do
begin
ShowMessage(e.Message+ inttostr(li_ESendSize));
end;
end; Gauge1.Progress := li_ESendSize;
inc(PRi_Sended , li_ESendSize);
end
else if PRSP_Protocol.Protocol = 'A' then
begin li_ReceiveSize := PRSP_Protocol.ReceiveSize ;
PRi_LostSize := PPFM_Send.Size - li_ReceiveSize ; PRFS_SendFile.Seek(li_ReceiveSize,soFromBeginning);
PPFM_Send.Flag := '0'; if PRi_LostSize > 1024 then
li_ESendSize := 1024
else
li_ESendSize := PRi_LostSize; try
PRFS_SendFile.ReadBuffer(SendBuf^, li_ESendSize);
Socket.SendBuf(SendBuf^, li_ESendSize);
except
On E:Exception do
begin
ShowMessage(e.Message+ inttostr(li_ESendSize));
end;
end; end else if PRSP_Protocol.Protocol = 'R' then
begin
if (PRi_Sended mod (2048*10)) = 0 then
begin
EndTime:= Now;
if EndTime - StartTime >0 then
begin
StatusBar1.Panels[2].Text :=
FloatToStrF(((PRi_Sended/1024)/((EndTime - StartTime) * 24 * 60 * 60)),
ffFixed,18,4)+'k/s';
end;
end;
li_ReceiveSize := PRSP_Protocol.ReceiveSize ;
PRi_LostSize := PPFM_Send.Size - li_ReceiveSize ;
if li_ReceiveSize >0 then
begin
PRFS_SendFile.Seek(li_ReceiveSize,soFromBeginning);
PPFM_Send.Flag := '0';
end; if PRi_LostSize > 1024 then
li_ESendSize := 1024
else
li_ESendSize := PRi_LostSize; try
PRFS_SendFile.ReadBuffer(SendBuf^, li_ESendSize);
Socket.SendBuf(SendBuf^, li_ESendSize);
except
On E:Exception do
begin
ShowMessage(e.Message+ inttostr(li_ESendSize));
end;
end; Gauge1.Progress := li_ReceiveSize + li_ESendSize;
inc(PRi_Sended , li_ESendSize);
end
else If PRSP_Protocol.Protocol= 'O' then
begin Memo2.Lines.Add('传输文件完成!');
PRFS_SendFile.Free ;
PPFM_Send.FileName := '';
PPFM_Send.Size := 0;
PRi_LostSize:= 0;
PRi_Sended := 0;
end;
end;
client//准备文件流
PRFS_SendFile := TFileStream.Create(Pb_ZipPath+trim(ls_BatchName)+'.Zip', fmOpenRead or fmShareDenyNone);
//发送文件名与长度
PPFM_Send.FileName :=ls_BatchName;
PPFM_Send.Size := PRi_LostSize ;
CSK_Send.Socket.SendBuf(PPFM_Send^,Sizeof(PPFM_Send^));
procedure TFrm_Client.CSK_SendRead(Sender: TObject;
Socket: TCustomWinSocket);
beginif PRSP_Protocol.Protocol = 'Y' then //服务端已准备好
begin if PRi_LostSize > 1024 then //如果剩下的文件大小大于4000,
li_ESendSize := 1024
else
li_ESendSize := PRi_LostSize; try
PRFS_SendFile.ReadBuffer(SendBuf^, li_ESendSize);
Socket.SendBuf(SendBuf^, li_ESendSize);
except
On E:Exception do
begin
ShowMessage(e.Message+ inttostr(li_ESendSize));
end;
end; Gauge1.Progress := li_ESendSize;
inc(PRi_Sended , li_ESendSize);
end
else if PRSP_Protocol.Protocol = 'A' then
begin li_ReceiveSize := PRSP_Protocol.ReceiveSize ;
PRi_LostSize := PPFM_Send.Size - li_ReceiveSize ; PRFS_SendFile.Seek(li_ReceiveSize,soFromBeginning);
PPFM_Send.Flag := '0'; if PRi_LostSize > 1024 then
li_ESendSize := 1024
else
li_ESendSize := PRi_LostSize; try
PRFS_SendFile.ReadBuffer(SendBuf^, li_ESendSize);
Socket.SendBuf(SendBuf^, li_ESendSize);
except
On E:Exception do
begin
ShowMessage(e.Message+ inttostr(li_ESendSize));
end;
end; end else if PRSP_Protocol.Protocol = 'R' then
begin
if (PRi_Sended mod (2048*10)) = 0 then
begin
EndTime:= Now;
if EndTime - StartTime >0 then
begin
StatusBar1.Panels[2].Text :=
FloatToStrF(((PRi_Sended/1024)/((EndTime - StartTime) * 24 * 60 * 60)),
ffFixed,18,4)+'k/s';
end;
end;
li_ReceiveSize := PRSP_Protocol.ReceiveSize ;
PRi_LostSize := PPFM_Send.Size - li_ReceiveSize ;
if li_ReceiveSize >0 then
begin
PRFS_SendFile.Seek(li_ReceiveSize,soFromBeginning);
PPFM_Send.Flag := '0';
end; if PRi_LostSize > 1024 then
li_ESendSize := 1024
else
li_ESendSize := PRi_LostSize; try
PRFS_SendFile.ReadBuffer(SendBuf^, li_ESendSize);
Socket.SendBuf(SendBuf^, li_ESendSize);
except
On E:Exception do
begin
ShowMessage(e.Message+ inttostr(li_ESendSize));
end;
end; Gauge1.Progress := li_ReceiveSize + li_ESendSize;
inc(PRi_Sended , li_ESendSize);
end
else If PRSP_Protocol.Protocol= 'O' then
begin Memo2.Lines.Add('传输文件完成!');
PRFS_SendFile.Free ;
PPFM_Send.FileName := '';
PPFM_Send.Size := 0;
PRi_LostSize:= 0;
PRi_Sended := 0;
end;
end;
解决方案 »
- PDF导出图像文件有没有相关的VCL?
- cxgrid 或 grid 中如何加入Popmenu呀????
- 在线等待(50分) 请问一个很菜的问题
- 在新增记录时,Query控件有没有象Table控件那样类似的方法
- 一个读INI文件的问题,谢了
- CSDN会不会根据各项指标给我们发点年终奖(专家分)?我在等待年终散分狂潮!!!实在是闲得慌啊,哈哈...
- ado的一个问题
- asp+delphi搞電子商務?
- 当主窗体最小化时,子窗体如何保持不动?
- 谈谈Delphi/C++ Builder和Visual Basic的本质区别吧
- 问一个关于虚方法的问题。自己做作业,不过有错,请大家帮我看看啊
- 请教:我form2继承于form1,我怎样控制父窗体中控件的位置在子窗体中不能移动呢!
procedure TFrm_Server.ServerSocket1ClientRead(Sender: TObject;
Socket: TCustomWinSocket);if PSockentPoninter(Socket.Data).flag = '1' then
begin if PPFM_Send.Flag = '0' then //开始传输新文件
begin
try
PSockentPoninter(Socket.Data).FileName := PPFM_Send.FileName ;
PSockentPoninter(Socket.Data).FileSize := PPFM_Send.Size ;
PSockentPoninter(Socket.Data).ReceiveSize := 0;
PSockentPoninter(Socket.Data).Ts_File :=
TFileStream.Create(Pb_RecievePath + ls_CurrentDate+'\'+ls_ClientID +
'\'+ls_SendID+ '\'+ls_WorkID +
'\'+PSockentPoninter(Socket.Data).FileName
+ '.MS!', fmCreate or fmShareDenyNone);
PSockentPoninter(Socket.Data).Ts_File.Seek(0, soFromBeginning);
//接收文件大小成功 //记录传输信息
PrF_AddSendMessage(PSockentPoninter(Socket.Data));
PSockentPoninter(Socket.Data).flag := '2'; //准备接收
//Socket.SendText('Y'); //通知客户
PRSP_Protocol.Protocol := 'Y';
PRSP_Protocol.ReceiveSize := 0; Socket.SendBuf(PRSP_Protocol^,Sizeof(PRSP_Protocol^));
except
end;
end
else if PPFM_Send.Flag = '1' then //传输中断的文件
begin
try
PSockentPoninter(Socket.Data).FileName := PPFM_Send.FileName ;
PSockentPoninter(Socket.Data).FileSize := PPFM_Send.Size ;
PSockentPoninter(Socket.Data).Ts_File :=
TFileStream.Create(Pb_RecievePath + ls_CurrentDate+'\'+ls_ClientID +
'\'+ls_SendID+'\'+ls_WorkID +
'\'+PSockentPoninter(Socket.Data).FileName
+ '.MS!', fmOpenReadWrite);
PSockentPoninter(Socket.Data).ReceiveSize := PSockentPoninter(Socket.Data).Ts_File.Size ; PSockentPoninter(Socket.Data).Ts_File.Seek(0, sofromend); ls_GuestID := PSockentPoninter(Socket.Data).GuestID; st_ReceiveSize.Caption :=
inttostr((strtoint(st_ReceiveSize.Caption) + PSockentPoninter(Socket.Data).ReceiveSize)) ; PSockentPoninter(Socket.Data).flag := '2'; //准备接收 PRSP_Protocol.Protocol := 'R';
PRSP_Protocol.ReceiveSize := PSockentPoninter(Socket.Data).ReceiveSize;
Socket.SendBuf(PRSP_Protocol^,Sizeof(PRSP_Protocol^));
except
end;
Panel1.Refresh ;
end;
end
else if PSockentPoninter(Socket.Data).flag = '2' then
begin
ls_CurrentDate := PSockentPoninter(Socket.Data).SendDate ;
ls_GuestID := PSockentPoninter(Socket.Data).GuestID ;
ls_ClientID := PSockentPoninter(Socket.Data).ClientID ;
ls_SendID := PSockentPoninter(Socket.Data).SendID ;
ls_WorkID := PSockentPoninter(Socket.Data).WorkID ;
//循环接收
repeat
li_ReceiveSize := socket.receivelength();
try
getmem(lP_ReceiveBuffer, li_ReceiveSize);
li_ReceiveSize := Socket.ReceiveBuf(lP_ReceiveBuffer^, li_ReceiveSize); if li_ReceiveSize > 0 then
begin PSockentPoninter(Socket.Data).Ts_File.Seek(0, sofromend);
PSockentPoninter(Socket.Data).Ts_File.WriteBuffer(lP_ReceiveBuffer^, li_ReceiveSize);
end;
except
on e:exception do
begin
Application.MessageBox(Pchar(e.Message ),'提示',mb_OK);
end;
end;
FreeMem(lP_ReceiveBuffer);
until (li_ReceiveSize <= 0);
PSockentPoninter(Socket.Data).ReceiveSize :=
PSockentPoninter(Socket.Data).Ts_File.Size ; if PSockentPoninter(Socket.Data).ReceiveSize =
PSockentPoninter(Socket.Data).FileSize then
Begin //准备下一次接收
ls_FileName := PSockentPoninter(Socket.Data).FileName ;
ls_CurrentDate := PSockentPoninter(Socket.Data).SendDate;
PSockentPoninter(Socket.Data).FileName := '' ;
PSockentPoninter(Socket.Data).FileSize := 0 ;
PSockentPoninter(Socket.Data).ReceiveSize := 0;
PSockentPoninter(Socket.Data).Ts_File.Free ;
PSockentPoninter(Socket.Data).Ts_File := nil;
PSockentPoninter(Socket.Data).flag := '1'; //修改文件名
RenameFile(Pb_RecievePath +ls_CurrentDate+ '\'+ls_ClientID +
'\'+ls_SendID +'\'+ls_WorkID +'\'+ls_FileName
+ '.MS!', Pb_RecievePath +ls_CurrentDate+ '\'+ls_ClientID +
'\'+ls_SendID +'\'+ls_WorkID +'\'+ls_FileName+'.Zip'); st_ReceiverPack.Caption := inttostr(strtoint(st_ReceiverPack.Caption)+1); PRSP_Protocol.Protocol := 'O';
PRSP_Protocol.ReceiveSize :=PSockentPoninter(Socket.Data).ReceiveSize;
Socket.SendBuf(PRSP_Protocol^,Sizeof(PRSP_Protocol^));
Panel1.Refresh ; end
else
begin //修改数据库中的记录信息
PRSP_Protocol.Protocol := 'A';
PRSP_Protocol.ReceiveSize :=PSockentPoninter(Socket.Data).ReceiveSize;
Socket.SendBuf(PRSP_Protocol^,Sizeof(PRSP_Protocol^));
//Socket.SendText('A'+FloattoStr(PSockentPoninter(Socket.Data).ReceiveSize));
end;
end;procedure TFrm_Server.ServerSocket1ClientConnect(Sender: TObject;
Socket: TCustomWinSocket);
var
lv_node:TListItem;
begin //得到一动态变量
New(Pr_PSockentPoninter);
Pr_PSockentPoninter.GuestAddr := Socket.RemoteAddress ; //客户地址
//标志 0表示下一步为验证密码
Pr_PSockentPoninter.flag := '0';
Socket.Data := Pr_PSockentPoninter; Memo1.Lines.Add('客户地址: '+ Socket.RemoteAddress +' 已连接');
st_Connect.Caption := inttostr(strtoint(st_Connect.Caption) +1);
Panel1.Refresh ;end;
lp_SendBuf为局部变量
GetMem(lP_SendBuf, 1024);
PRFS_SendFile.ReadBuffer(lP_SendBuf^, li_ESendSize);
try
Socket.SendBuf(lP_SendBuf^, li_ESendSize);
finally
FreeMem(lP_SendBuf) ;
end;
在我的本机上没有问题,如果每次发送比1024大,在internet上每次发到最后,都要出现收到的比源文件大的问题。发1024非常稳定
为什么要分片一应一答的传呢?TCP层已经保证的传输的可靠性,不应该再在应用程序这层上面做这样的事情了.
你程序的通讯效率其实可以大大提高的.既然通讯协议这样定了,就定了吧:)
观察到你代码中一个重要问题...
居然楼主从来没有取Sendbuf的返回值进行判断..
仅仅是在代码外面抓了异常(非阻塞这样的情况,这儿抓异常一点用都没有)
因此,它的调用返回是非常快的(没做什么实质的事情当然快)它有两种返回值,成功表示这块数据已经写进本地SOCKET缓冲队列,
失败表示缓冲已满,你需要延时重发这整块数据.
特别注意,除了返回值,这时候不会有任何异常抛出!
服务端
repeat
li_ReceiveSize := socket.receivelength();
try
getmem(lP_ReceiveBuffer, li_ReceiveSize);
li_ReceiveSize := Socket.ReceiveBuf(lP_ReceiveBuffer^, li_ReceiveSize); if li_ReceiveSize > 0 then
begin PSockentPoninter(Socket.Data).Ts_File.Seek(0, sofromend);
PSockentPoninter(Socket.Data).Ts_File.WriteBuffer(lP_ReceiveBuffer^, li_ReceiveSize);
end;
except
on e:exception do
begin
Application.MessageBox(Pchar(e.Message ),'提示',mb_OK);
end;
end;
FreeMem(lP_ReceiveBuffer);
until (li_ReceiveSize <= 0);
客户端
if PRi_LostSize > 8192 then
li_ESendSize := 8192
else
li_ESendSize := PRi_LostSize; PRFS_SendFile.ReadBuffer(SendBuf^, li_ESendSize); repeat
try
li_SendedSize := Socket.SendBuf(SendBuf^, li_ESendSize);
except
On E:Exception do
begin
ShowMessage(e.Message+ inttostr(li_ESendSize));
end;
end;
if li_SendedSize <0 then
begin
Sleep(100);
end;
if li_SendedSize <> 8192 then
begin
Memo1.Lines.Add(inttostr(li_SendedSize)) ;
end;
until (li_SendedSize >= 0);
每次发8192,我本机通过,不知到在internet上能否通过,等我测试好后在来
這是系統的設定吧, 一般系統會設置最大的ip包大小, 超過了, 就分自動分包!也可能與控件的緩衝區大小有關