Client端一次只能只能传输1024字节,为什么?

cqzyf 2004-07-11 11:38:46
客户端向服务端发送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);
begin

if 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;

...全文
582 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
myling 2004-09-22
  • 打赏
  • 举报
回复
up
cqzyf 2004-07-22
  • 打赏
  • 举报
回复
感谢大家,问题解决!
aiirii 2004-07-14
  • 打赏
  • 举报
回复
>>Client端一次只能只能传输1024字节,为什么?
這是系統的設定吧, 一般系統會設置最大的ip包大小, 超過了, 就分自動分包!

也可能與控件的緩衝區大小有關
cqzyf 2004-07-14
  • 打赏
  • 举报
回复
我现在已经改为
服务端
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上能否通过,等我测试好后在来
cqzyf 2004-07-13
  • 打赏
  • 举报
回复
先谢谢halfdream(哈欠) ,我做测试后在来。
power_yhb 2004-07-13
  • 打赏
  • 举报
回复
哈哈,有问题QQ联系:250648556,包你满意.
cqzyf 2004-07-11
  • 打赏
  • 举报
回复
怎么没有人啊?
bxh2dai 2004-07-11
  • 打赏
  • 举报
回复
先测试一下!就结果再说
cqzyf 2004-07-11
  • 打赏
  • 举报
回复
我去吃饭,中午再来,希望大家提提自己的看法
halfdream 2004-07-11
  • 打赏
  • 举报
回复
非阻塞模式下,Sendbuf只是写数据到本地SOCKET的内部缓冲队列,
因此,它的调用返回是非常快的(没做什么实质的事情当然快)

它有两种返回值,成功表示这块数据已经写进本地SOCKET缓冲队列,
失败表示缓冲已满,你需要延时重发这整块数据.
特别注意,除了返回值,这时候不会有任何异常抛出!

cqzyf 2004-07-11
  • 打赏
  • 举报
回复
服务端

服务端
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;
halfdream 2004-07-11
  • 打赏
  • 举报
回复
为什么要这么做呢??
为什么要分片一应一答的传呢?TCP层已经保证的传输的可靠性,不应该再在应用程序这层上面做这样的事情了.
你程序的通讯效率其实可以大大提高的.

既然通讯协议这样定了,就定了吧:)


观察到你代码中一个重要问题...
居然楼主从来没有取Sendbuf的返回值进行判断..
仅仅是在代码外面抓了异常(非阻塞这样的情况,这儿抓异常一点用都没有)


halfdream 2004-07-11
  • 打赏
  • 举报
回复
天啦..能不能把代码改短些...

cqzyf 2004-07-11
  • 打赏
  • 举报
回复
我做了改动
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非常稳定
cqzyf 2004-07-11
  • 打赏
  • 举报
回复
不会没有人没有遇到这个问题吧?
pilicat 2004-07-11
  • 打赏
  • 举报
回复
帮你UP
cqzyf 2004-07-11
  • 打赏
  • 举报
回复
但我用1024速度实在无法忍受,用4096速度要快4到6倍,我又式了,每次到最后时都会报错,我检查文件,收到的文件比发送的还大。也就是说发了100k,实际可能收到了101k
aiirii 2004-07-11
  • 打赏
  • 举报
回复
代码太长,没细看,理论上,发送的文件格式是没有区别的,不会是zip就不行,bmp就行!

系统是会限制IP包的大小的,你在程序改大,用处不大,超过了, 系统还是会拆包发送的

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧