利用socket进行文件分割传输

Arctic_snow 2009-04-13 06:10:54

一个窗体同时作为发送和接收端,所以client的ip已经设好127.0.0.1,而且端口也已经设好。一些变量设为静态。

我使用它传一个图片,接收下来的图片有重叠。但不调试发现执行一次ClientWrite,接收方执行ServerClientRead不是一次,而是两次。

我真搞不明白了。所以那位高手做过诸如此类的程序,请指教!

具体程序如下:

/---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "UCommunicate.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

static int final,emod=0,hui=0,x=0,a=0,i=0;

TMainFrm *MainFrm;
//---------------------------------------------------------------------------
__fastcall TMainFrm::TMainFrm(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TMainFrm::ClientWrite(TObject *Sender,
TCustomWinSocket *Socket)
{
void *p[20000];
static long k=20000;
static long bmpsize,c,mod;
static TMemoryStream* pms = new TMemoryStream();
if(hui==0)
{pms->LoadFromFile(filename);hui++; //装入要发送的文件。
bmpsize=pms->Size; //计算文件的大小(字节)
c=(int)bmpsize/k; //分割文件为c
mod=bmpsize%k; //分割后于下的字节数
emod=mod; //使mod在整个程序都可访问
}
if(i<c)
{
pms->Position=x; //改变内存流读取指针
pms->ReadBuffer(p,k); //把内存流读入缓冲区
x=x+k;
Client->Socket->SendBuf(p,k); //将分割的文件发送
i++ ;
}
else
{
final++;
pms->Position=x;
pms->ReadBuffer(p,mod); //发送最后mod个字节后,发送完毕
Client->Socket->SendBuf(p,mod);


}


}
//---------------------------------------------------------------------------
void __fastcall TMainFrm::Button1Click(TObject *Sender)
{
if(OpenDialog1->Execute())
{
filename = OpenDialog1->FileName;
Label1->Caption="选择图片成功";
hui=0; a=0; final=0;
x=0; i=0;
}
}
//---------------------------------------------------------------------------
void __fastcall TMainFrm::ClientConnect(TObject *Sender,
TCustomWinSocket *Socket)
{
Label1->Caption="ok";
}
//---------------------------------------------------------------------------
void __fastcall TMainFrm::ServerClientRead(TObject *Sender,
TCustomWinSocket *Socket)
{
static TMemoryStream* qms = new TMemoryStream();
void *z[20000]; //定义缓冲区大小

if(final!=1)
{
Socket->ReceiveBuf(z,20000); //接收SOCKET中的数据流
qms->Position=a;
qms->WriteBuffer(z,20000); //写入缓冲区
a=a+20000; //改变内存流指针
Client->Active=false; //每次发送前要判断网络是否畅通
Client->Port=8888; //联接远程计算机,如果成功则 发送,否则等待
Client->Active=true;
}
else //接收最后emod个字节。
{
qms->WriteBuffer(z,emod);
qms->SaveToFile("g:\\ok.bmp");
Label1->Caption="successful";
qms->Position=0;
Image1->Picture->Bitmap->LoadFromStream(qms);
}

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

void __fastcall TMainFrm::Button2Click(TObject *Sender)
{
Client->Active=false;
Client->Port=8888;
Client->Active=true;

}
//---------------------------------------------------------------------------
...全文
207 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
pp616 2009-04-17
  • 打赏
  • 举报
回复
void *p[20000]; 定义的缓冲区有80000个字节而实际只用到了20000 有点浪费

Socket->ReceiveBuf(z,20000); //接收SOCKET中的数据流
20000在这里无意义。并不是发送方sendbuf是给定的是20000 接收方就一定可以收到那么多。
应该调用ReceiveLength()来取收到了多少字节。Socket->ReceiveBuf(z, Socket->ReceiveLength());

在ServerClientRead里
Client->Active=false; //每次发送前要判断网络是否畅通
Client->Port=8888; //联接远程计算机,如果成功则 发送,否则等待
Client->Active=true;
每收到一次数据就把client断开重连。这么做实在有点另类。。。 为什么不一次把数据发送完再断开。

windows socket的发送缓冲区和接收缓冲区大小不一定是相同的,sendbuf的次数和ClientRead事件并不是一一对应的。1次sned引发多次recv很正常,多次send引发1次recv也很正常。
缓冲区具体大小可以用 getsockopt 函数来查

1,316

社区成员

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

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