SendBuf与ReceiveBuf数据不一致。

supercboy 2010-06-21 10:22:26
//文件传输的问题,发送速度一快,就会出现发送数据和接收数据不一致,发的多,接的少,有时发的少接的多。郁闷死了。
//下面是原代码。看看问题出在那里了。谢谢。分数不多了。只能上这么些了。
filepart=flen;(文件长度。以前是文件块数,但有问题,接收发送块不一致,就改成文件字节数了。)
filepart_len=0;//已发送的长度,用来在文件类中定位取数据用。
void __fastcall TMain::clsoketConnect(TObject *Sender,
TCustomWinSocket *Socket)
{
if(filepart_send==0)
Socket->SendText("\3\3\3\3"+t_filename+"*"+IntToStr(flen));
}
//---------------------------------------------------------------------------


void __fastcall TMain::svsoketClientRead(TObject *Sender,
TCustomWinSocket *Socket)
{

Application->ProcessMessages();
if(!recfile_bool)
{
AnsiString Msgs=Socket->ReceiveText();
recfile_bool=true;
if(Msgs.SubString(1,4)=="\3\3\3\3")
{
filenowlen=StrToInt(Msgs.SubString(Msgs.LastDelimiter("*")+1,Msgs.Length()-Msgs.LastDelimiter("*"))) ;
Msgs=Msgs.SubString(1,Msgs.LastDelimiter("*")-1);
if(!r_filename.Trim().IsEmpty())
Msgs=r_filename+Msgs.SubString(Msgs.LastDelimiter("\\"),Msgs.Length()-Msgs.LastDelimiter("\\"));
else
Msgs=ExtractFilePath(Application->ExeName)+Msgs.SubString(Msgs.LastDelimiter("\\")+1,Msgs.Length()-Msgs.LastDelimiter("\\"));
r_filename=Msgs;
if(FileExists(r_filename))
DeleteFile(r_filename);
fh=FileCreate(r_filename);
Socket->SendText("\1\1\1\1#0");
return;
}
}
else
{
char buff[8192];
int reclen=0;
FileSeek(fh,0,2);
do
{
reclen=Socket->ReceiveBuf(buff,sizeof(buff));
if(reclen>0)
{
recnum=recnum+reclen;
if(!FileWrite(fh,buff,reclen))
ShowMessage("写入错误!");
}
//Sleep(1);//这里加上Sleep(1)后,接收就正常了。但速度奇慢。局域网内!

}while(reclen>0);
cg1->Progress=recnum/(filenowlen/100);
if(recnum==filenowlen)
{
recfile_bool=false;
FileClose(fh);
svsoket->Close();
pnl1->Visible=false;
ShowMessage("接收结束!");
return;
}
if(Socket->Connected)
{
Socket->SendText("\1\1\1\1#"+IntToStr(recnum));
}
return;
}

}
//---------------------------------------------------------------------------

void __fastcall TMain::clsoketRead(TObject *Sender,
TCustomWinSocket *Socket)
{

char buf[8192];
AnsiString getstr="";
getstr=Socket->ReceiveText();
if(getstr.SubString(1,4)=="\1\1\1\1")
{
unsigned long receivelen=StrToInt(getstr.SubString(getstr.LastDelimiter("#")+1,getstr.Length()-5));
//if(filepart_send!=receivelen)
// ShowMessage("error");
filepart_send=receivelen;
if(filepart_send==filepart && filepart>0)
{
pnl1->Visible=false;
ShowMessage("发送结束!");
filestream->Free();
return;
}
int readlen=0;
int sendlen=0;
filestream->Seek(filepart_send,soFromBeginning);
readlen=filestream->Read(buf,sizeof(buf));
if(sendlen=Socket->SendBuf(buf,readlen))
{
filepart_send=filepart_send+sendlen;
cg1->Progress=filepart_send/(filepart/100);
cg1->Refresh();
}
if(filepart_send>=filepart && filepart>0)
{
pnl1->Visible=false;
ShowMessage("发送结束!");
filestream->Free();
}
}
...全文
261 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
supercboy 2010-06-24
  • 打赏
  • 举报
回复
已经改好了。不用循环,用循环是有问题的。不贴代码了。说一下原理:
一来一往式,分包发。我定义的包大小是8192Byte
sendbuf就不说了。
问题出在receivebuf
因为接收时你查看实际接的receivelen时,并一定接收完了。这个值是不定的。发送慢的话等于包长,快的话小于包长,关键就在于,如果一包数据一次没有接完,会继续触发ServerSocketClientRead事件。所以在下一事件处理没发完的。
这时可定义一个临时int 变量 int tmp_len=tmp_len+receivelen;
判断tmp_len,如果tmp_len==包长,写入文件或TFileStream,再回信息让发另一包
直到总接收长度等于文件长度算发完。
谢谢大家。
sue3140 2010-06-23
  • 打赏
  • 举报
回复
我是写一个结构,在结构里面定义了头,数据长度等等
接收方同样的结构定义,循环接收
xuzhu3000 2010-06-23
  • 打赏
  • 举报
回复
头大,是在看不下去。
我只知道我做图像传输的时候,在ClientRead时间里也做了个循环,后来发现,这样不好,因为每次有数据来都触发一次ClientRead,虽然循环结束了,克ClientRead还要触发。所以后来,我就改了。在发送方的文件前加4个字节的头,4个字节的len,接收方判断4个字节的头,如果是,判断长度,如果长度一样,就读取。不一样,就继续往流里写。我用的是TMemoryStream。
我传的图片大概30k,一次传不完,过程:
第一次:大概8192字节,用Stream->position,可以移动位置。判断头4个字节,发现一样,获取len信息;
第二次:判断头四个字节,发现不一样,继续往流里写文件;
……过程就这样
supercboy 2010-06-21
  • 打赏
  • 举报
回复
这是截取的一段代码,变动太多次,有点乱!呵呵!但整体思路是这样的∶发送方先发filename 和filelen给接收方,并把文件读入文件类Filestream,接收方创建文件后发送消息1111#+已收长度给发送方,发送方接到消息后分解读取位置(即接收方已接收的长度)读取8192字节到buf然后发送,接收方接受后存入文件,依次循环至结束
周药师 2010-06-21
  • 打赏
  • 举报
回复
没有格式 看了就头晕

1,317

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder 网络及通讯开发
社区管理员
  • 网络及通讯开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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