用Socket 文件传输,传大文件时,接收的文件损坏,这是怎么回事呢?

icemoon1987 2008-07-21 02:56:27
我是一名刚开始学MFC的大学生,试着编了一个用socket传输文件的程序。
思路是把文件一次性读入缓冲区,然后用TCP发送,接收方一次性把文件接收入缓冲区,然后再写成文件。
我试着用这个程序传送了一些小的文本文件,一切正常,也传了一些MP3,正常。
但是在传送一些100多M的RMVB视频文件时,接收到的文件却无法打开
请问各位高手这是怎么回事呢?谢谢了。

该开始学,分不多,请见谅。

程序代码如下:

服务器端:

void CFileTransDlg::OnSend()
{
// TODO: Add your control notification handler code here

CFileDialog fd(true);
CString filename;
char fn[40];

SOCKET listenSocket;
SOCKET socketSend;
unsigned int listen_port;


CFile file;
int FileLength;
char *data;

struct sockaddr_in localaddr;
struct sockaddr_in clientaddr;

listen_port=5050;

int AddrSize;

AddrSize = sizeof(clientaddr);

if(IDOK == fd.DoModal())
{

filename = fd.GetFileName();
if(!file.Open(filename.GetBuffer(0),CFile::modeRead|CFile::typeBinary))
{
AfxMessageBox("打开文件错误,取消发送!");
return;
}
strcpy(fn,filename.GetBuffer(0));

}
else return;

listenSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
socketSend = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

localaddr.sin_addr.s_addr = htonl(INADDR_ANY);
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(listen_port);


if (bind(listenSocket, (struct sockaddr *)&localaddr,
sizeof(localaddr)) == SOCKET_ERROR)
{
AfxMessageBox("绑定socket失败 : %d\n", WSAGetLastError());
return ;
}


listen(listenSocket,20);


socketSend = accept(listenSocket,(struct sockaddr *)&clientaddr,&AddrSize);

FileLength = file.GetLength();


char acBuf[50] = { 0 };
sprintf(acBuf, "%d", FileLength);

send(socketSend,acBuf,50,0);
send(socketSend,fn,40,0);

data = new char[FileLength];

file.ReadHuge(data,FileLength);

send(socketSend,data,FileLength,0);



file.Close();
delete data;
closesocket(socketSend);

WSACleanup();

}

客户端:

void CFileTransClientDlg::OnReceive()
{
// TODO: Add your control notification handler code here

SOCKET socketReceive;
CFile file;
long FileLength = 0;
char tem[50];
char *data;
char fn[40];
struct sockaddr_in server;
unsigned int server_port=5050;

server.sin_family = AF_INET;
server.sin_port = htons(server_port);
server.sin_addr.s_addr = inet_addr("222.25.136.114");


InitWinsock();

socketReceive = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

connect(socketReceive,(struct sockaddr *)&server,sizeof(server));

recv(socketReceive,tem,50,0);

FileLength = chartoint(tem);

recv(socketReceive,fn,40,0);

data = new char[FileLength];

recv(socketReceive,data,FileLength,0);

file.Open(fn,CFile::modeCreate |CFile::modeWrite|CFile::typeBinary);

file.WriteHuge(data,FileLength);

file.Close();

delete data;

closesocket(socketReceive);

AfxMessageBox("接收文件成功!");

WSACleanup();

}
...全文
754 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
ang3659467 2010-10-09
  • 打赏
  • 举报
回复
继续学习!!!!
liaoning33 2010-08-09
  • 打赏
  • 举报
回复
icemoon1987 2008-07-21
  • 打赏
  • 举报
回复
哦,我明白了,我想接收那边我也能写出来了,太谢谢你了!
剩下的我自己尝试吧。

嘿嘿,要学的东西真是太多了,太感谢了!!
thirddata 2008-07-21
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 icemoon1987 的回复:]
哦,太谢谢了。我大概有思路了。
但是现在还不明白一个地方。
Send函数有三个参数,我要怎样确定它从那个字节开始发呢?
还是我把没发完的数据再放入另一个缓冲区,然后调用Send发送呢?
另外recv函数,要怎么样才能控制它接收了数据后加入刚才的缓冲区后面呢?
还是我要重新开辟一片缓冲区,然后接受完后,再连接起来?
[/Quote]
int nLeft = nLength;
while(nLeft > 0){
//can write
int nSent = ::send(s,
pszBuffer + (nLength - nLeft),nLeft,0);
if(SOCKET_ERROR == nSent){
//error
break;
}
else{
nLeft -= nSent;
}
}
icemoon1987 2008-07-21
  • 打赏
  • 举报
回复
哦,太谢谢了。我大概有思路了。
但是现在还不明白一个地方。
Send函数有三个参数,我要怎样确定它从那个字节开始发呢?
还是我把没发完的数据再放入另一个缓冲区,然后调用Send发送呢?
另外recv函数,要怎么样才能控制它接收了数据后加入刚才的缓冲区后面呢?
还是我要重新开辟一片缓冲区,然后接受完后,再连接起来?
icemoon1987 2008-07-21
  • 打赏
  • 举报
回复
恩,是不是一个Send函数一次发送的数据有个最大限制啊?

如果要再次发送剩余数据的话,我怎么知道刚才发送到哪儿了呢?

不好意思啊,我是个初学者,还什么多不太懂。

能不能麻烦你说的详细一点?
谢谢了!
thirddata 2008-07-21
  • 打赏
  • 举报
回复
比如你发送char szBuffer[1024],
调用一次send,send返回512,说明这次send只发送成功了512字节
应该再次调用send,发送下面的512字节,
去看msdn
thirddata 2008-07-21
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 icemoon1987 的回复:]
谢谢啊,我刚开始学,对于Socket和TCP的理解还很浅。

我用一个Send语句传送文件,是系统自动把这个文件分成很多份在打包发送的吗??

如果是的话,是不是接收后系统自动在把这些包组合起来?
我应该怎样才能加上验证呢?

不麻烦你帮忙写代码,只要讲一下思路就可以了。另外能告诉我该去看书上的那一部分相关知识吗?
我想把这个问题弄清楚。

再次谢谢了!
[/Quote]
系统不会帮你分包的,你应该检查send的返回值,看看是否所有数据都发送了,如果只发送了部分数据,继续发送下面的数据,recv一样的道理
icemoon1987 2008-07-21
  • 打赏
  • 举报
回复
谢谢啊,不过我刚开始学,还不太会用。
能不能再说得稍微详细一些呢,谢谢。
不麻烦你帮忙写代码,只要讲一下思路就可以了。另外能告诉我该去看书上的那一部分相关知识吗?
thirddata 2008-07-21
  • 打赏
  • 举报
回复
这样的代码,当然那有问题了
1,每个send函数的返回值
2,每个recv函数的返回值
3,如果send函数返回的值没有发送完所有数据,需要再次发送剩余数据。
检查一下啊
icemoon1987 2008-07-21
  • 打赏
  • 举报
回复
谢谢啊,我刚开始学,对于Socket和TCP的理解还很浅。

我用一个Send语句传送文件,是系统自动把这个文件分成很多份在打包发送的吗??

如果是的话,是不是接收后系统自动在把这些包组合起来?
我应该怎样才能加上验证呢?

不麻烦你帮忙写代码,只要讲一下思路就可以了。另外能告诉我该去看书上的那一部分相关知识吗?
我想把这个问题弄清楚。

再次谢谢了!
ouyh12345 2008-07-21
  • 打赏
  • 举报
回复
用非阻塞的socket,循环读、写
西山小月 2008-07-21
  • 打赏
  • 举报
回复
最好加上一些验证,每个包都有序号
基于P2P的局域网即通信系统+项目说明(c#源码)计算机网络课程设计.zip 基于P2P的局域网即通信系统+项目说明(c#源码)计算机网络课程设计.zip 基于P2P的局域网即通信系统+项目说明(c#源码)计算机网络课程设计.zip 【资源说明】 该项目是个人毕设项目源码,评审分达到95分,调试运行正常,确保可以运行!放心下载使用。 该项目资源主要针对计算机、自动化等相关专业的学生或从业者下载使用,也可作为期末课程设计、课程大作业、毕业设计等。 具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现类似其他功能。 ### 已知技术参数和设计要求 1.掌握P2P原理。\ 2.实现一个图形用户界面局域网内的消息系统。\ 3.功能:建立一个局域网内的简单的P2P消息系统,程序既是服务器又是客户,服务器端口(自拟服务器端口号并选定)。\ 3.1用户注册及对等方列表的获取:对等方A启动后,用户设置自己的信息(用户名,所在组);扫描网段中在线的对等方(服务器端口打开),向所有在线对等方的服务端 口发送消息,接收接收到消息后,把对等方A加入到自己的用户列表中,并发应答消息;对等方A把回应消息的其它对等方加入用户列表。双方交换的消息格式自己根据 需要定义,至少包括用户名、IP地址。\ 3.2发送消息和文件:用户在列表中选择用户,与用户建立TCP连接,发送文件或消息。\ 4.用户界面:界面上包括对等方列表;消息显示列表;消息输入框;文件传输进程显示及操作按钮或菜单。 ### 已经实现的功能 #### 核心功能 用户的注册与登录(一台电脑最多一个账户);\ UDP上下线广播,对等方的账户信息交换;\ TCP聊天消息交换,支持本地历史记录保存(rtf)和未读消息提示(xml);\ TCP文件传输(每次只能和一个人传文件),支持详细的进度显示和中断传输(可能有bug); #### 额外功能 弹出式通知气泡;\ 设置页面:用户名更改,清空本机数据,免密登录等; ### 放弃的功能 好友系统(局域网就几台电脑,搞好友系统好像没有必要);\ 多人文件传输(懒得搞);\ 优化 UID 的生成方式(懒得搞×2); ### 已知 BUG (严重)向虚拟机用户发送文件(>40MB),且传输速度高于5MB/s,极高概率会发生文件损坏。原因尚不清楚;\ 若接收方中断文件传输,发送方极小概率会抛出 “往已释放的 SOCKET 写入数据” 错误,但是可以忽略(catch 改一下,让它不抛出错误就好了);\ 当局域网列表里的人全部下线,而用户正处于文件传输页面,小概率会不跳转回局域网页面,而这会让用户误操作,向不存在的用户发送文件;

18,356

社区成员

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

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