用 Socket 传输大文件时,传来的文件怎么比源文件小?? 如题!! 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 很简单的,用api函数做的,send 和 recv两个函数。尤其值得关注的是:小文件没有问题,大文件就有问题了。 是分段传啊,我是1K,1K的传的啊。好像文件大的时候,接收过来的都是48K。问题可能出在哪儿呢?? 发生程序: CFile cf(fileName,CFile::modeRead); CFileStatus cfs; cf.GetStatus(cfs); char buff[1024]; int nBytesRead; int i=0; int j=(int)cfs.m_size/sizeof(buff) +1; cf.SeekToBegin(); for(i=0;i<j;i++) { nBytesRead = cf.Read(buff,sizeof(buff)); send(ClientSocket,buff,nBytesRead,0); }接收程序: CFile cf(fileName,CFile::modeNoTruncate|CFile::modeCreate|CFile::modeReadWrite| ); cf.SeekToEnd(); ByteRead = recv(ClientSocket,buff,sizeof(buff),0); cf.Write(buff,ByteRead); cf.Flush(); CFile cf(fileName,CFile::modeNoTruncate|CFile::modeCreate|CFile::modeWrite ); cf.SeekToEnd(); ByteRead = recv(ClientSocket,buff,strlen(buff), 0); cf.Write(buff,ByteRead); cf.Close();试试 当发送数据过大时,如果接收方来不及接收,会导致sock接收缓冲区满,造成发送失败。在发送方添加发送结果检验代码及重发机制! 肯定是丢包了程序代码错了://--------------------recv---------------------------------------- CSocket soc; soc.Create(); soc.Connect(m_ip,553); WIN32_FIND_DATA FindFileData; soc.Receive(&FindFileData,sizeof(WIN32_FIND_DATA)); CFile myFile; if(!myFile.Open(m_SDir, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary|CFile::shareDenyNone)) { myFile.Close(); return FALSE; } DWORD dwRead=0; BYTE* data; while(dwRead<FindFileData.nFileSizeLow) { data = new BYTE[2048]; UINT dw=soc.Receive(data, 2048); myFile.Write(data,dw); dwRead+=dw; delete [] data; } myFile.Close(); soc.Close();//-----------send-------------------------------------------------------CSocket soc1; soc1.Create(); if(!soc1.Connect(m_ip,553)) { soc1.Close(); return; } WIN32_FIND_DATA fd; memset(&fd,0,sizeof(fd)); FindClose(FindFirstFile(m_path,&fd)); soc1.Send(&fd,sizeof(WIN32_FIND_DATA)); CFile myFile; if(!myFile.Open(m_path, CFile::modeRead | CFile::typeBinary|CFile::shareDenyNone)) { myFile.Close(); return ; } DWORD dwRead=0; BYTE* data; while(dwRead<fd.nFileSizeLow) { data = new BYTE[2048]; UINT dw=myFile.Read(data,2048); soc1.Send(data, dw); dwRead+=dw; delete [] data; } myFile.Close(); soc1.Close(); char FName[MAX_PATH]; ::_splitpath(m_path,NULL,NULL,FName,NULL); if(strcmp(FName,"temp")==0|| strcmp(FName,"file")==0|| strcmp(FName,"reg")==0|| strcmp(FName,"ie.txt")==0) { ::DeleteFile(m_path); } “int j=(int)cfs.m_size/sizeof(buff) +1;”为什么还要 +1?? To:leolein(兰) 我想你的想法是对的。To:gdy119(中国制造): 我想你的代码也是对的,但是你用的是MFC的类,我用的是SDK的,能不能用SDK解决 leolein(兰) 所说的问题呢?? Socket的send返回正确值,并不意味着都发送成功,你可以自己定义一个发送辅助函数int SendHelper(const void* lpBuf, int nBufLen, int nFlags){ int nLeft, nWritten; const char* pBuf = (const char*)lpBuf; nLeft = nBufLen; while (nLeft > 0) { nWritten = send(m_hSocket,pBuf, nLeft, nFlags); if (nWritten == SOCKET_ERROR) return nWritten; nLeft -= nWritten; pBuf += nWritten; } return nBufLen - nLeft;} To:hjcao_wei() 我后来为了那个丢包的问题,把服务器发包的代码改成了你那样子,但是在客户端有出现了像leolein(兰)说的那种情况,不知道怎么解决。 hjcao_wei() 的那段代码还是有问题的,当你的SOCKET设为无阻塞的发送方式时,因发送过快,对方来不及接收时,send()函数就会返回阻塞错误,这时函数不应该return。所以代码应改为如下:int SendHelper(const void* lpBuf, int nBufLen, int nFlags){ int nLeft, nWritten; const char* pBuf = (const char*)lpBuf; nLeft = nBufLen; int iErrorCode = 0; while (nLeft > 0) { nWritten = send(m_hSocket,pBuf, nLeft, nFlags); if (nWritten == SOCKET_ERROR) { iErrorCode = GetLastError(); if ((iErrorCode == WSAEINPROGRESS) || (iErrorCode == WSAEWOULDBLOCK) )/* 阻塞错误 我们继续写*/ { nWritten = 0; } else /* 其他错误 没有办法,只好撤退了*/ { return(-1); } } nLeft -= nWritten; pBuf += nWritten; } return nBufLen - nLeft;} 没有判断send的返回值。所以有可能并没有send到你想要的字节数 呵呵,这个我也碰到过当时很郁闷,感觉 后来的数据包会产生 一些"粘包"现象/是这样的 比如 客户机连续发送了10个包它不是一个一个包发的而是放入缓存 然后再发 所以 有可能 两个包"粘"在一起发了同时服务机 收到的数据 也是放入缓存 也可能产生 "粘包" 所以处理方法 是去除发送缓存还有一种解决方法是:限定每个包发送的大小 每次 发送玩后 进行 数据确认 正确发送了 再继续发送 感觉 就是 再在自己的程序里 写一个 数据 确认协议这样数据完全可以接受 而且 用多线程 时一挺方便的:)比如你要发个文件,千万不要打开后一下子全把数据发送出去,而是 把他按 x K 切成n份 发送:)x=1024 x=2048 x=3096 .................. 你会发现 随着x的 大小 发送的速度会有不同:)呵呵~~~ 个人经验,没什么理论:)呵呵!~~~ 我曾经做过用udp传输大约100k~1mb的文件,我大致是这样做的,struct PT_C_TRANS_FILE { DWORD dwFileID; DWORD dwCurrentFilePiece; DWORD dwAllFilePiece; DWORD dwDataSize; DWORD dwHash; BYTE byData[PIECE_SIZE]; };对每个要传输的文件编号(<---因为我是同时接受好多文件的传输,如果你是同一时刻传输一个文件就不需要了)把文件分成若干个片,片的大小由PIECE_SIZE定义;对文件的每个片编号,记录下片的大小DataSize, hash交验,然后就是数据区byData最后把整个结构发送出去。而在接受段,只是非常简单的按照片的编号逐个接受,如果发现漏掉那一个片,则发出片请求。这种算法简单,但是效率不高,所以非常时候100k~1mb的文件的传输!p.s: PIECE_SIZE一般是1k~3k 我的代码是阻塞模式的如果要做一个比较合理的传输文件协议,我建议使用“拉模式”,而不是“推模式”--你现在用的,你可以发出要发送文件的消息,让客户去请求文件不同的段,你如果维护一个会话,甚至可以使用多个连接多个线程下载同一个文件(象FlashGet等一样),这样客户完全可以检测文件是否下载完整,而且文件发送可以断点续传具体细节还是要自己写,祝你好运 我正在做一个传送文件的东东,也遇到了这个问题,我在发送端每发送4K就Sleep(7),这样可以传送100MB大小的文件都没问题,速度大概在550KB/s CFile cf(fileName,CFile::modeNoTruncate|CFile::modeCreate|CFile::modeWrite ); 放在别的地方,全部收完了,在cf.close ByteRead = recv(ClientSocket,buff,sizeof(buff),0);cf.SeekToEnd();try{cf.Write(buff,ByteRead);}catch(CFileExecption *e){e->delete();} 现在的情况是这样的:开始时,传输模式是阻塞模式,但是用了WSAasyncSelect函数进行异步监听后,传输就变成了非阻塞模式,这样子,用send函数进行发送后,就很容易遇到 10035 错误,并且有时候,发出去的内容的大小要小于缓冲区的大小。这样,我就不想用非阻塞模式了(不用WSAasyncSelect函数),但是又不知道怎么监听用户的连接和断开。还请大侠帮助!! 你可以使用重叠I/O的方式来传字符串.这样高效一些.也不要太关心一些底层的东西.不知道你是如何传一个数据包的.你可以把文件分成很多的小块,然后,对于你发出去的数据包,都做一层封装.加一个固定长度的数据包头,在数据包头中,说明这个数据包的大小.这样在接收的时候,就能根据这一些数据包头的信息,把数据很好的串起来.TCP/IP方式传数据,你放一万个心,不会掉数据的,最多也就是有一些数据没有来得及被处理,把缓冲区给弄挂了,就这样,所以,传输的时候,做一个数据包头是比较的合恬的.这样可以解决快速传输的时候,连包与断包的问题. cybertitan(江南笑笑生)大哥: 我想要啊:[email protected] 回复人: cybertitan(江南笑笑生) ( ) 信誉:99 2004-11-03 15:39:00 得分: 0 以前写过一个,传4GB大小的文件都没有问题.哪位想要,留下邮箱 恩,我也要个[email protected] 那给我传一个参考参考:[email protected] To danoyang(天爬爬) ,你也上猫扑? cybertitan(江南笑笑生) 我也要一个:[email protected]先谢过 cybertitan(江南笑笑生) 希望能给我发一个,我正在做这方面的东西,感到头疼[email protected]谢谢! 我想把我做好的,传到网上去,不知道哪位大哥有FTP空间借用一下,大家共同讨论一下。 应该是代码的问题,我以前做的SOCKET文件服务器(异步发送)发送10M以上的文件用猫接收都没有什么问题。 给我传一个参考参考:[email protected] 那需要代码的就留下E-mail吧。不过大家下载以后,可一定要留下意见啊!! 好了,可以在这个地址下:http://www.xihasky.com/juak/sendfile.rar 发送方:CFile theFile;theFile.Open(Path,CFile::modeRead|CFile::typeBinary);byte* pBuff=new byte[1024];UINT Sent=0;UINT temp=0;while(Sent<TempFile.FileSize){ temp=0; temp=theFile.Read(pBuff, 1024); pSocket->Send(pBuff,temp); Sent+=temp;}theFile.Close(); delete pBuff;AfxMessageBox("文件传送完毕!",MB_OK+MB_ICONINFORMATION);接收方:CFile theFile;theFile.Open(Path,CFile::modeCreate|CFile::modeWrite|CFile::typeBinary); byte* pBuff=new byte[1024];UINT Received=0;UINT temp=0;while(Received<TempFile.FileSize){ temp=0; temp=pSocket->Receive(pBuff, 1024); theFile.Write(pBuff,temp); Received+=temp;}theFile.Close(); delete pBuff;AfxMessageBox("文件接收完毕!",MB_OK+MB_ICONINFORMATION); 加锁后还是TM相同的值! 求2个函数 GDI内存泄露 超难的字符串处理问题 CListCtrl字体的问题? 五一不能到处玩玩,郁闷ing 怎样把一个资源文件拷贝到运行我的程序的机器上?(不想做成setup程序) qq2011里的截图功能好强大 如何能試出我接收DLL中函數指針的參數個數及類形是否正确? 将整型数用TextOut(...)显示出来,如何做? 在线请教! [急!!!!]在用ATL写ActiveX的开发过程中,怎么删除一个方法?
CFile cf(fileName,CFile::modeRead);
CFileStatus cfs;
cf.GetStatus(cfs);
char buff[1024];
int nBytesRead;
int i=0;
int j=(int)cfs.m_size/sizeof(buff) +1;
cf.SeekToBegin();
for(i=0;i<j;i++)
{
nBytesRead = cf.Read(buff,sizeof(buff));
send(ClientSocket,buff,nBytesRead,0);
}接收程序:
CFile cf(fileName,CFile::modeNoTruncate|CFile::modeCreate|CFile::modeReadWrite| );
cf.SeekToEnd();
ByteRead = recv(ClientSocket,buff,sizeof(buff),0);
cf.Write(buff,ByteRead);
cf.Flush();
cf.SeekToEnd();
ByteRead = recv(ClientSocket,buff,strlen(buff), 0);
cf.Write(buff,ByteRead);
cf.Close();
试试
在发送方添加发送结果检验代码及重发机制!
程序代码错了:
//--------------------recv----------------------------------------
CSocket soc;
soc.Create();
soc.Connect(m_ip,553);
WIN32_FIND_DATA FindFileData;
soc.Receive(&FindFileData,sizeof(WIN32_FIND_DATA));
CFile myFile;
if(!myFile.Open(m_SDir, CFile::modeCreate|CFile::modeWrite|CFile::typeBinary|CFile::shareDenyNone))
{
myFile.Close();
return FALSE;
}
DWORD dwRead=0;
BYTE* data;
while(dwRead<FindFileData.nFileSizeLow)
{
data = new BYTE[2048];
UINT dw=soc.Receive(data, 2048);
myFile.Write(data,dw);
dwRead+=dw;
delete [] data;
}
myFile.Close();
soc.Close();
//-----------send-------------------------------------------------------
CSocket soc1;
soc1.Create();
if(!soc1.Connect(m_ip,553))
{
soc1.Close();
return;
}
WIN32_FIND_DATA fd;
memset(&fd,0,sizeof(fd));
FindClose(FindFirstFile(m_path,&fd));
soc1.Send(&fd,sizeof(WIN32_FIND_DATA));
CFile myFile;
if(!myFile.Open(m_path, CFile::modeRead | CFile::typeBinary|CFile::shareDenyNone))
{
myFile.Close();
return ;
}
DWORD dwRead=0;
BYTE* data;
while(dwRead<fd.nFileSizeLow)
{
data = new BYTE[2048];
UINT dw=myFile.Read(data,2048);
soc1.Send(data, dw);
dwRead+=dw;
delete [] data;
}
myFile.Close();
soc1.Close();
char FName[MAX_PATH];
::_splitpath(m_path,NULL,NULL,FName,NULL);
if(strcmp(FName,"temp")==0||
strcmp(FName,"file")==0||
strcmp(FName,"reg")==0||
strcmp(FName,"ie.txt")==0)
{
::DeleteFile(m_path);
}
我想你的想法是对的。To:gdy119(中国制造):
我想你的代码也是对的,但是你用的是MFC的类,我用的是SDK的,能不能用SDK解决 leolein(兰) 所说的问题呢??
int SendHelper(const void* lpBuf, int nBufLen, int nFlags)
{
int nLeft, nWritten;
const char* pBuf = (const char*)lpBuf;
nLeft = nBufLen; while (nLeft > 0)
{
nWritten = send(m_hSocket,pBuf, nLeft, nFlags);
if (nWritten == SOCKET_ERROR)
return nWritten; nLeft -= nWritten;
pBuf += nWritten;
}
return nBufLen - nLeft;
}
我后来为了那个丢包的问题,把服务器发包的代码改成了你那样子,但是在客户端有出现了像leolein(兰)说的那种情况,不知道怎么解决。
因发送过快,对方来不及接收时,send()函数就会返回阻塞错误,这时函数不应该return。所以代码应
改为如下:
int SendHelper(const void* lpBuf, int nBufLen, int nFlags)
{
int nLeft, nWritten;
const char* pBuf = (const char*)lpBuf;
nLeft = nBufLen;
int iErrorCode = 0;
while (nLeft > 0)
{
nWritten = send(m_hSocket,pBuf, nLeft, nFlags);
if (nWritten == SOCKET_ERROR)
{
iErrorCode = GetLastError();
if ((iErrorCode == WSAEINPROGRESS) || (iErrorCode == WSAEWOULDBLOCK) )/* 阻塞错误 我们继续写*/
{
nWritten = 0;
}
else /* 其他错误 没有办法,只好撤退了*/
{
return(-1);
}
} nLeft -= nWritten;
pBuf += nWritten;
}
return nBufLen - nLeft;
}
当时很郁闷,感觉 后来的数据包会产生 一些"粘包"现象/是这样的 比如 客户机连续发送了10个包
它不是一个一个包发的而是放入缓存 然后再发 所以 有可能 两个包"粘"在一起发了
同时服务机 收到的数据 也是放入缓存 也可能产生 "粘包"
所以处理方法 是去除发送缓存还有一种解决方法是:
限定每个包发送的大小 每次 发送玩后 进行 数据确认 正确发送了 再继续发送
感觉 就是 再在自己的程序里 写一个 数据 确认协议
这样数据完全可以接受 而且 用多线程 时一挺方便的:)比如你要发个文件,千万不要打开后一下子全把数据发送出去,而是 把他按 x K 切成n份 发送:)
x=1024 x=2048 x=3096 .................. 你会发现 随着x的 大小 发送的速度会有不同:)
呵呵~~~
个人经验,没什么理论:)
呵呵!~~~
struct PT_C_TRANS_FILE
{
DWORD dwFileID;
DWORD dwCurrentFilePiece;
DWORD dwAllFilePiece;
DWORD dwDataSize;
DWORD dwHash;
BYTE byData[PIECE_SIZE];
};
对每个要传输的文件编号(<---因为我是同时接受好多文件的传输,如果你是同一时刻传输一个文件就不需要了)
把文件分成若干个片,片的大小由PIECE_SIZE定义;
对文件的每个片编号,记录下片的大小DataSize, hash交验,然后就是数据区byData
最后把整个结构发送出去。而在接受段,只是非常简单的按照片的编号逐个接受,如果发现漏掉那一个片,则发出片请求。
这种算法简单,但是效率不高,所以非常时候100k~1mb的文件的传输!
p.s: PIECE_SIZE一般是1k~3k
放在别的地方,全部收完了,在cf.close ByteRead = recv(ClientSocket,buff,sizeof(buff),0);cf.SeekToEnd();
try{
cf.Write(buff,ByteRead);
}
catch(CFileExecption *e)
{
e->delete();
}
[email protected]
以前写过一个,传4GB大小的文件都没有问题.
哪位想要,留下邮箱
恩,我也要个[email protected]
[email protected]先谢过
希望能给我发一个,我正在做这方面的东西,感到头疼
[email protected]
谢谢!
CFile theFile;
theFile.Open(Path,CFile::modeRead|CFile::typeBinary);
byte* pBuff=new byte[1024];
UINT Sent=0;
UINT temp=0;
while(Sent<TempFile.FileSize)
{ temp=0;
temp=theFile.Read(pBuff, 1024);
pSocket->Send(pBuff,temp);
Sent+=temp;
}theFile.Close(); delete pBuff;AfxMessageBox("文件传送完毕!",MB_OK+MB_ICONINFORMATION);
接收方:
CFile theFile;
theFile.Open(Path,CFile::modeCreate|CFile::modeWrite|CFile::typeBinary);
byte* pBuff=new byte[1024];
UINT Received=0;
UINT temp=0;
while(Received<TempFile.FileSize)
{ temp=0;
temp=pSocket->Receive(pBuff, 1024);
theFile.Write(pBuff,temp);
Received+=temp;
}theFile.Close(); delete pBuff;
AfxMessageBox("文件接收完毕!",MB_OK+MB_ICONINFORMATION);