文件传输WriteFile出错

yangt1100 2010-05-19 09:03:19
服务器端:


typedef struct _MsgFormat
{
int type; //信息类型
char msg[2048]; //信息内容
long length;//信息长度
}MsgFormat;

//发送文件
DWORD dwRead;
BOOL bOk;
MsgForamt recvMsg;

HANDLE hFile=CreateFile(strFileName,GENERIC_READ,0,0,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,0); //创建文件句柄
while(1)
{
dwRead=0;
memset(recvMsg.msg,0,2048);
bOk=ReadFile(hFile,recvMsg.msg,2048,&dwRead,NULL);//读取文件
if(bOk==FALSE)
{
dlg->PendLog("读取文件出错!");
break;
}
else if(dwRead==0)
{
recvMsg.type=9; //读取文件完成标志
int nSend=::send(socket,(char*)&recvMsg,sizeof(recvMsg),0);//发送文件传送完成标志
if(nSend>0)
{
PendLog("用户 "+strUserName+"发送文件"+strFileName1+"完毕");
}
else
{
MessageBox(_T("发送完毕信息失败"),_T("失败"),MB_OK|MB_ICONERROR);
}
break;
}
else
{
recvMsg.type=2; //发送信息标志
recvMsg.length=dwRead;
int nSend=::send(pSocketClient->s,(char*)&recvMsg,sizeof(recvMsg),0);//发送文件信息
if(nSend<=0)
{
break;
}
}
}
CloseHandle(hFile);//关闭文件句柄



客户端代码:

typedefstruct_MsgFormat
{
inttype;//信息类型
charmsg[2048];//信息内容
longlength;//信息长度
}MsgFormat;

DWORDdwWrite;
boolbOk;
MsgFormat recvMsg;

//创建文件句柄 strFileName为文件名
HANDLE hFile=CreateFile(strFileFullName,GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
while(1)
{
memset(recvMsg.msg,0,2048);
int read=::recv(socket,(char*)&recvMsg,sizeof(recvMsg),0); //读取服务器端发送的文件
if(read<=0)
break;

if(recvMsg.type==9)//如果发送的为完成标志则退出
break;

int length=0;
length=recvMsg.length;//服务器端发送信息的长度
bOk=WriteFile(hFile,recvMsg.msg,length,&dwWrite,NULL);//将信息写入到文件中
if(bOk==FALSE)
{
MessageBox(_T("文件写入失败!"),_T("文件下载失败"),MB_OK|MB_ICONERROR);
break;
}
if(dwWrite==0)
break;

}
AfxMessageBox(_T("文件下载完成"));
CloseHandle(hFile);


上述代码是我从我的一个文件传送的小程序中摘录的一部分,其中在客户端将接收到的信息写入到文件时经常有错误发生。
当我发送一个几KB的文件时可以顺利的传完,但发送超过1M左右的文件时就会提示“文件写入失败”,也就是在客户端的WriteFile函数返回FALSE。但奇怪的是当我用相同文件进行单步调试时有不会有出错提示。有哪位高手能不能看看代码看看有什么不完善的地方,请指正!谢谢
...全文
175 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
快乐鹦鹉 2010-05-20
  • 打赏
  • 举报
回复
你可以在发送文件之前,首先发送文件的长度。这样客户端就知道需要接收多少信息了。这样,你每次都不需要发送type内容。客户端接收结束的标志就是已经完全接收完一开始发过来的文件长度值的串信息。
yangt1100 2010-05-19
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 happyparrot 的回复:]
我已经说了,不需要length进行传递,那么你recv收到的内容的前4个字节不就是type了么。后面的内容就是数据了。
你文件每次读2048是没错。但是,如果nSend不等于dwRead+4,那么你需要将文件指针前移。
比如nSend = 1024;那么实际传输的内容就是1024-4 = 1020字节。那么文件指针就要向前移动dwRead-1020字节。

而且,仔细考虑,发送这种结构本身……
[/Quote]

非常感谢!我仔细研究后发现问题就出现在结构体中的length上。我以前也试过用char*来传输文件信息,但当服务器端读到文件末尾时客户端并不知道,客户端的recv函数就会一直阻塞。如果我在服务器端读到文件末尾时发送一个特定字符串告知客户端退出时,客户端有时并不能准确判断这个结束标志。
快乐鹦鹉 2010-05-19
  • 打赏
  • 举报
回复
我已经说了,不需要length进行传递,那么你recv收到的内容的前4个字节不就是type了么。后面的内容就是数据了。
你文件每次读2048是没错。但是,如果nSend不等于dwRead+4,那么你需要将文件指针前移。
比如nSend = 1024;那么实际传输的内容就是1024-4 = 1020字节。那么文件指针就要向前移动dwRead-1020字节。

而且,仔细考虑,发送这种结构本身就是不合适的。假设你这个结构不能一次发完呢?那么,剩余的部分就不会有type信息了,但实际你客户端还会按照有type的情况去处理。所以整个思路就不正确。

yangt1100 2010-05-19
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 happyparrot 的回复:]
length=recvMsg.length;//服务器端发送信息的长度
==我觉得这有问题。为什么要传长度信息呢?客户端接收到多少,完全是看你的recv返回值read是多少,而不是看你这个recvMsg结构中的length。
结构中不需要这个长度信息,服务端也不应该固定用文件读取的位置来读取下一段,而是应该用nSend来确定文件下一部分的读取起始位置。
[/Quote]

如果用recv返回读取到的信息长度,那么read应该还包含结构体中的其它两个参数的大小(type、length),怎样才能取得接收文件信息的长度呢?
另外,服务器端怎样根据上一次发送信息的长度来确定下一次读取文件的开始位置?
谢谢!
zyq5945 2010-05-19
  • 打赏
  • 举报
回复
send发送的返回值是发送了多少字节,还要检查一下是否真的都发送过去了。
WriteFile的时候你是按2048来写了,recv接收估计没有那么大。
你打印看下你send和recv的字节就知道了。
快乐鹦鹉 2010-05-19
  • 打赏
  • 举报
回复
length=recvMsg.length;//服务器端发送信息的长度
==我觉得这有问题。为什么要传长度信息呢?客户端接收到多少,完全是看你的recv返回值read是多少,而不是看你这个recvMsg结构中的length。
结构中不需要这个长度信息,服务端也不应该固定用文件读取的位置来读取下一段,而是应该用nSend来确定文件下一部分的读取起始位置。
yangt1100 2010-05-19
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 zyq5945 的回复:]
GetLastError查看错误原因。
[/Quote]

我试了试发现每次返回的错误都不一样,很是郁闷
zyq5945 2010-05-19
  • 打赏
  • 举报
回复
GetLastError查看错误原因。

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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