能力值:
( LV2,RANK:10 )
|
-
-
2 楼
这个是发送的代码:
void CMyServerXDlg::OnButton2()
{
if(m_bConnected)
{
CFileDialog dlg(
true,
"",
"",
OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,
"所有文件(*.*)|*.*||",
NULL);
int structsize=0;
DWORD dwVersion=::GetVersion();
DWORD dwWindowMajorVersion,
dwWindowMinorVersion;
dwWindowMajorVersion=(DWORD)(LOBYTE(LOWORD(dwVersion)));
dwWindowMinorVersion=(DWORD)(HIBYTE(LOWORD(dwVersion)));
if(dwVersion<0x80000000)
structsize=88;
else
structsize=76;
dlg.m_ofn.lStructSize=structsize;
dlg.m_ofn.Flags=dlg.m_ofn.Flags|OFN_SHOWHELP|OFN_LONGNAMES;
CString FilePathName;
if(dlg.DoModal()==IDOK)
{
FilePathName=dlg.GetPathName();
CFile myFile;
myFile.Open((LPTSTR)(LPCTSTR)FilePathName,CFile::modeRead|CFile::typeBinary,NULL);
int len=myFile.GetLength();
for(int i=0;i<len;i+=1024)
{
if(i+1024>len)
{
int byteNum=len-i;
if(byteNum==1)
{
socket.Send(&byteNum,sizeof(int),0);
BYTE* buffer=new BYTE[byteNum];
memset(buffer,0,byteNum);
myFile.ReadHuge(buffer,byteNum);
socket.Send(buffer,byteNum,0);
delete []buffer;
break;
}
else if(byteNum>1)
{
int byteNumX=byteNum-1;
socket.Send(&byteNumX,sizeof(int),0);
BYTE* buffer=new BYTE[byteNumX];
memset(buffer,0,byteNumX);
myFile.ReadHuge(buffer,byteNumX);
socket.Send(buffer,byteNumX,0);
delete []buffer;
byteNumX=1;
socket.Send(&byteNumX,sizeof(int),0);
buffer=new BYTE[byteNumX];
memset(buffer,0,byteNumX);
myFile.ReadHuge(buffer,byteNumX);
socket.Send(buffer,byteNumX,0);
delete []buffer;
break;
}
else
AfxMessageBox("传输发生错误!",MB_OK);
}
else if(i+1024<=len)
{
const int byteNum=1024;
socket.Send(&byteNum,sizeof(int),0);
BYTE* buffer=new BYTE[1024];
memset(buffer,0,1024);
myFile.ReadHuge(buffer,1024);
socket.Send(buffer,1024,0);
delete []buffer;
} else
AfxMessageBox("传输发生错误!",MB_OK);
}
myFile.Close();
}
else
return;
}
else
AfxMessageBox("服务器尚未连接!",MB_OK);
}
|
能力值:
( LV2,RANK:10 )
|
-
-
3 楼
接收的代码:
void CMySocket::OnReceive(int nErrorCode)
{
CMyServerXDlg* pDlg=(CMyServerXDlg*)AfxGetApp()->GetMainWnd();
pDlg->m_edit1.SetWindowText("开始接收客户端信息……");
int byteNum=0;
Receive(&byteNum,sizeof(int),0);
BYTE* buffer=new BYTE[byteNum];
memset(buffer,0,byteNum);
Receive(buffer,byteNum,0);
myFile.WriteHuge(buffer,byteNum);
delete []buffer;
if(byteNum==1)
{
myFile.Close();
pDlg->m_edit1.SetWindowText("信息接收完毕!");
}
CSocket::OnReceive(nErrorCode);
}
|
能力值:
( LV9,RANK:190 )
|
-
-
4 楼
不是消息缓存大小的问题。你的程序本身有问题。
两个问题:
1、接收到100M的问题:
考虑如下情况:server 发一个包,bytenum =8196(4 + 8192) ,网络传输分成4096 + 2052。
第一次 CMySocket::OnReceive( int nErrorCode)时, 收到4096,固然好。然后第二次 CMySocket::OnReceive(int nErrorCode)时, 第一个Receive(sizeof(int) )收到的是消息的第 4097~4010 这四个字节。第二个第一个Receive()就取决了这四个字节值的大小了。
2、 CSocket::OnReceive(nErrorCode) 不能主动调用。它是个虚函数,在有消息到达时,它自动被系统调用,它再调用继承它的CMySocket::OnReceive(int nErrorCode)。你这里其实是一个递归循环。
解决办法自己研究吧。有问题的话把源程序附件上来
|
能力值:
( LV2,RANK:10 )
|
-
-
5 楼
我懂您的意思,我就是为了避免这种情况,专门把要发送的文件自己分了包。每个包的大小都是1024个字节(当然最后一个包可能不够这个数目),然后再循环地一个个发送出去。(详细可见我红色部分的代码)
但是这样做不出问题的前提是:系统不会再对1024字节大小的包进行再分包,如果再分的话,立刻就会出现您说的问题。
目前这个代码,对大多数文件的传输没啥问题,但是小部分文件还是会出现错误,原因不明。
|
能力值:
( LV9,RANK:190 )
|
-
-
6 楼
给你一个“发一次错一次,发十次错十次”的办法。你看看你的程序是不是“大多数文件的传输没啥问题”。
比如:你要发一个大小为10,内容为字串"0000000000"的文件,你按下面的办法发送:
先发送一个整数10, 再发送6个字节,再发送4个字节。那么你客户端写的文件就是3158064+ 10 个字节。3兆。
比如:你要发一个大小为10,内容为字串"0000001111"的文件,你按下面的办法发送:
先发送一个整数10, 再发送6个字节,再发送4个字节。那么你客户端写的文件就是51458353 + 10 个字节。50兆。
|
能力值:
( LV2,RANK:10 )
|
-
-
7 楼
厄。。。这样不对啊
根据接收方的代码
先发送整数10,那么接收方申请缓冲区10字节,后面再发送的6个字节就被填入该缓冲区内(不足的补0)。
再发送4字节,刚好又是一个int类型的长度,但是由于字串都是"0000000000",所以接收方不会申请缓冲区的……
算了,干脆附上源码
|
能力值:
( LV2,RANK:10 )
|
-
-
8 楼
有人指教下吗?
|
能力值:
( LV2,RANK:10 )
|
-
-
9 楼
建议这样的程序使用一个单独的报头来定义文件的大小,报头有固定长度,接收到报头以后,再开始文件的传输.
一个TCP包大小一般为1500byte.像这样的程序楼主可以去www.vckbase.com上看,有很多例子.
|
能力值:
( LV9,RANK:190 )
|
-
-
10 楼
void CMySocket::OnReceive(int nErrorCode)
{
CMyServerXDlg* pDlg=(CMyServerXDlg*)AfxGetApp()->GetMainWnd();
pDlg->m_edit1.SetWindowText("开始接收客户端信息……");
static bool newMsg = true;
static int byteNum= 0;
static int len = 0;
static BYTE* buffer = NULL;
int templen;
// 新的文件传输,则先收一下文件长度
if ( newMsg )
{
newMsg = false;
Receive(&byteNum,sizeof(int),0);
length = byteNum;
buffer = new BYTE[byteNum];
}
//接收剩下的部分文件 byteNum - len 是应该收的长度,templen是实际收到的长充
templen = Receive( buffer, byteNum - len , 0 );
myFile.WriteHuge( buffer, templen );
len += templen;
if ( len == byteNum )
//一个文件接收完毕
{
delete []buffer;
myFile.Close();
pDlg->m_edit1.SetWindowText("信息接收完毕!");
//准备接收新文件
newMsg = true;
}
}
|
能力值:
( LV2,RANK:10 )
|
-
-
11 楼
多谢这位大虾
看了你的代码,确实比我的优秀不少啊
|
能力值:
( LV4,RANK:50 )
|
-
-
12 楼
楼上各位:TCP编程中没有“包”的概念!
用UDP编程的方法写TCP程序,简单网络或许没问题,在稍微复杂的网络中,比如跨网段、使用中介代理服务、跨介质等情况,会出现乱七八糟的问题的。
如果你们为了实现应用协议非要用“包”,请不要嫌麻烦,在发送和接收时参照TCP的特性处理好块大小、块确认、块接收,否则有你们受罪的时候。
一点建议,认为我说错了,就当我放屁吧
|
能力值:
( LV8,RANK:130 )
|
-
-
13 楼
UDP的话,缓冲窗口,块顺序,块分片,包重发,包重复检测等都是要自己做的
|