A-A+

MFC大文件传输

2014年02月15日 MFC开发 评论 2 条 阅读 263 次

MFC大文件传输核心思想(C/C++程序员之家自己研究的,请大家指出不当之处,以便更正):

首先先给下CSDN上论坛对TCP大文件传输的讨论:

TCP发送端速度过快,有可能造成堵塞,发送缓冲区满之后就会丢数据,然后就造成数据不准确了。

  1. 解决方法一、设置发送缓冲区成更大的值(不提倡)。
  2. 解决方法二、使用确认包,每次只发一个小包,客户端收到后向服务端发“确认”反馈,服务端等收到“完成”后再发下一个包。
  3. 解决方法三、采用完成端口技术……

所以我们要考虑大文件的时候,是否数据正常接收。这里,最好采用“确认机制”,或者是“文件分割编号机制",文件分割方法个人感觉较好,在客户端可以方便组装!如果还是不能正常接收文件建议大家检查数据是否丢包(或者服务器线程简单的休眠(Sleep),调试程序)。

大文件传输结构体模型

[cpp]

typedef struct tagPic
{
UINT FileLength; //文件大小
BYTE data[1024]; //图片数据buff
int id; //分块id号
int Count; //分块数量
int last; //每次最终成功发送的数据量
}PIC;

[/cpp]

1、接下来思路是:服务器文件传输线程分块儿读取文件发包,然后封装成普通消息发给客户端。客户端接收来自服务器端的消息,判断是否是文件传输消息,如果是文件传输消息,直接交给客户端文件传输线程,最后判断id和last只需分块而写入文件即可!

2、理论上支持大文件传输,测试了200M以上的无压力,更大的文件的没有测试,BYTE data[1024],可以根据消息容纳字节数,自己调整buff缓冲区。

备注:TCP可能的丢包现象:

简单写了一个传输JPG图片的程序,图片但是只能显示一半,下半部分图片无法正常显示(花屏)!因为会发生阻塞,所以研究了好长时间,结果加上一个Sleep(300),服务器发过一次数据之后休眠,解决了此问题。

服务器端:

[cpp]

AfxSocketInit(NULL);
CSocket sockSrvr;
sockSrvr.Create(PORT);
sockSrvr.Listen();
CSocket sockRecv;
sockSrvr.Accept(sockRecv);
CFile tFile;
tFile.Open(_T("C:\\Cache.jpg"), CFile::modeRead | CFile::typeBinary);
ULONGLONG myFileLength = tFile.GetLength();
sockRecv.Send(&myFileLength, 8); //先发送文件大小

byte buff[1024];int reVal;
memset(buff,0,1024);
int Count = myFileLength/1024+1;
if(myFileLength%1024==0) --Count;
for (int i=0;i<Count;i++) //移位、读取1024字节、发送真实字节数
{
tFile.Seek(i*1024,CFile::begin);
reVal=tFile.Read(buff,1024);
sockRecv.Send(buff,reVal);
Sleep(300); //TCP发包过快,会产生丢包现象。
}

tFile.Close();
sockRecv.Close();

[/cpp]

客户端:

[cpp]

AfxSocketInit(NULL);
CSocket sockClient;
sockClient.Create();
sockClient.Connect(_T("192.168.4.78"), PORT);
ULONGLONG dataLength;
sockClient.Receive(&dataLength, 8);

byte buff[1024];
int Count = dataLength/1024+1;
if(dataLength%1024==0) --Count;
CFile tFile(_T("C:\\Cache.jpg"), CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
for (int i=0;i<Count;i++)//会发生阻塞,所以用 了for循环监听
{
if (i==Count-1) //最后一次数据
{
sockClient.Receive(buff,dataLength-i*1024);
tFile.Seek(i*1024,CFile::begin);
tFile.Write(buff,dataLength-i*1024);
}
else
{
sockClient.Receive(buff,1024);
tFile.Seek(i*1024,CFile::begin);
tFile.Write(buff,1024);
}
}
tFile.Close();
sockClient.Close();

[/cpp]

标签:

2 条留言  访客:2 条  博主:0 条

  1. vfhky

    sleep的值用不了那么大,1就足够了。

  2. heyuan

    路过学习学习

给我留言

Copyright © C/C++程序员之家 保留所有权利.   Theme  Ality 浙ICP备15011757号-3

用户登录