CAsyncSocket类OnReceive接收数据

时间:2023-01-06 16:59:02
提问:OnReceive 如何接受一个完整的数据包?
现接收的数据包格式如下:
struct _senddata_
{
int msgid;//消息ID
size_t datasize;
char *buff;
};
发送时,这个数据包是被压到一个 char *sendbuff; 中的,接受这个数据要先从sendbuff中取出msgid和datasize,然后再根据datasize接受数据。

CAsyncSocket类的OnReceive是基于消息机制的,由于不太了解CAsyncSocket类,所以不知道如何完整接受这个数据包,并且不会出现断包,连包等情况。

我的解决办法如下(这个解决办法有问题):
void CServerappDlg::OnReceive(CMySocket *asyncSocket)
{
char str[50]={0};//接受数据头数据的buff

        static size_t datalen=0;//已读取的数据长度
static char *buff=NULL;//保存接收的数据包buff
static int msgid;//数据包的消息ID,用于识别数据消息类型
static size_t datasize;//数据包的长度
int ret;

do
{
if (buff == NULL)
{//数据头
ret = asyncSocket->Receive(str,sizeof(msgid)+sizeof(datasize));

if (ret >= 0)
{
memcpy(&msgid,str,sizeof(msgid));
memcpy(&datasize,str+sizeof(msgid),sizeof(datasize));
if (datasize == 0)//只有消息ID的数据包
{
DealWithMsgData(asyncSocket,msgid,buff,datasize);
break;
}
buff = (char*)malloc(datasize);//申请空间
datalen = 0;
}
}
else
{//数据buff
ret = asyncSocket->Receive(buff+datalen,datasize-datalen);
if (ret > 0)
{
if (datalen+ret >= datasize)//数据包读取完成
{
//处理包数据
//msgid是包消息类型 datasize 是数据包大小 buff是数据包内容
OutputDebugString(buff);
DealWithMsgData(asyncSocket,msgid,buff,datasize);//处理接收数据的函数,这个可以自己定义

                                        //释放包数据
free(buff);
datasize=0;
datalen=0;
buff = NULL;
break;
}
else
{
datalen += ret;
}
}
else
{//出现错误?
int error;
error = asyncSocket->GetLastError();
char str[260];
wsprintf(str,"服务端错误代码:%d",error);
MessageBox("接收失败!",str);
SetLastError(0);
break;
}
}
}while(ret > 0);

}


这个解决办法一开始还可以用,但是接收几十个数据包后就出现异常,CAsyncSocket类的OnReceive就无法接收到数据了 CAsyncSocket类OnReceive接收数据
所以在这里请教各位大神!麻烦帮我看看,哪里出现问题了?感谢!!!

9 个解决方案

#1


代码加了很多注释了,希望能看懂!

#2


为了更好的发现问题所在,我把发送数据的代码也贴上来吧
int CMySocket::SendData(int msgid,char *buff, size_t buffsize)//参数分别是消息ID,发送的数据,发送数据的大小
{
char *sendbuff=NULL;
int ret=0,count=0;
sendbuff = (char*)malloc(buffsize+sizeof(msgid)+sizeof(buffsize));
memcpy(sendbuff,&msgid,sizeof(msgid));
memcpy(sendbuff+sizeof(msgid),&buffsize,sizeof(buffsize));
memcpy(sendbuff+sizeof(msgid)+sizeof(buffsize),buff,buffsize);

 //以下是发送的主要代码---------------------------------------------------------------------------
ret = Send(sendbuff,buffsize+sizeof(buffsize)+sizeof(msgid));

int sendsize = buffsize+sizeof(buffsize)+sizeof(msgid);
for (int sendpos=ret; sendpos < sendsize; sendpos += ret)
{
ret = Send(sendbuff+sendpos,sendsize-sendpos);
Sleep(1);
}
free(sendbuff);//释放buff
//----------------------------------------------------------------------------------------------------------
return ret;
}

#3


ret = asyncSocket->Receive(str,sizeof(msgid)+sizeof(datasize));

这句代码不一定能够返回你想要收到的数据长度,你应该循环收取,直到满足你的长度要求为止:

char szBuf[8192[;
char *pos= szBuf;
int nIndex = 0;
int nRecvLen= sizeof(msgid) + sizeof(datasize);

while (1)
{
     int len = asyncSocket->Receive(pos+ nIndex,  nRecvLen - nIndex);
     if (len <= 0)
     {
             TRACE("Receive Error: %ld\n", WSAGetLastError());
             break;
     }

     nIndex += len;
     if (nIndex == nRecvLen ) 
     {
           break;
     }
}

// 
//  你的数据处理代码

#4


引用 3 楼 shenyi0106 的回复:
ret = asyncSocket->Receive(str,sizeof(msgid)+sizeof(datasize));

这句代码不一定能够返回你想要收到的数据长度,你应该循环收取,直到满足你的长度要求为止:

char szBuf[8192[;
char *pos= szBuf;
int nIndex = 0;
int nRecvLen= sizeof(msgid) + sizeof(datasize);

while (1)
{
     int len = asyncSocket->Receive(pos+ nIndex,  nRecvLen - nIndex);
     if (len <= 0)
     {
             TRACE("Receive Error: %ld\n", WSAGetLastError());
             break;
     }

     nIndex += len;
     if (nIndex == nRecvLen ) 
     {
           break;
     }
}

// 
//  你的数据处理代码

谢谢!请问在消息机制下可以这样接收数据吗?

#5


引用 4 楼 qq1412198766 的回复:
Quote: 引用 3 楼 shenyi0106 的回复:

ret = asyncSocket->Receive(str,sizeof(msgid)+sizeof(datasize));

这句代码不一定能够返回你想要收到的数据长度,你应该循环收取,直到满足你的长度要求为止:

char szBuf[8192[;
char *pos= szBuf;
int nIndex = 0;
int nRecvLen= sizeof(msgid) + sizeof(datasize);

while (1)
{
     int len = asyncSocket->Receive(pos+ nIndex,  nRecvLen - nIndex);
     if (len <= 0)
     {
             TRACE("Receive Error: %ld\n", WSAGetLastError());
             break;
     }

     nIndex += len;
     if (nIndex == nRecvLen ) 
     {
           break;
     }
}

// 
//  你的数据处理代码

谢谢!请问在消息机制下可以这样接收数据吗?

可以,而且必须要这样收

#6


引用 5 楼 shenyi0106 的回复:
Quote: 引用 4 楼 qq1412198766 的回复:

Quote: 引用 3 楼 shenyi0106 的回复:

ret = asyncSocket->Receive(str,sizeof(msgid)+sizeof(datasize));

这句代码不一定能够返回你想要收到的数据长度,你应该循环收取,直到满足你的长度要求为止:

char szBuf[8192[;
char *pos= szBuf;
int nIndex = 0;
int nRecvLen= sizeof(msgid) + sizeof(datasize);

while (1)
{
     int len = asyncSocket->Receive(pos+ nIndex,  nRecvLen - nIndex);
     if (len <= 0)
     {
             TRACE("Receive Error: %ld\n", WSAGetLastError());
             break;
     }

     nIndex += len;
     if (nIndex == nRecvLen ) 
     {
           break;
     }
}

// 
//  你的数据处理代码

谢谢!请问在消息机制下可以这样接收数据吗?

可以,而且必须要这样收

谢谢!可是我又发现一个问题,可能是问题的关键所在:
int len = asyncSocket->Receive(pos+ nIndex,  nRecvLen - nIndex);
当这一句接受数据量太大的话,这句是否会导致socket缓冲区溢出?我记得socket的缓冲区好像是固定大小的,溢出之后CAsyncSocket类的OnReceive()消息是否就再也收不到了?

#7


socket缓冲区溢出的可能性已经排除,现在问题还是没有解决,现在的问题主要如下:

1、服务端能发送数据。
2、客户端接收服务端的数据成功,发送也成功。
3、服务端没能收到客户端发送的数据,CAsyncSocket类并没有通知OnReceive()消息有数据接收。

问题就是出现在第3步,CAsyncSocket类没有通知OnReceive()消息。可是这个问题又是怎么触发出来的?纳闷中。。
大神们求解。。

#8


非常感谢:shenyi0106
问题已经解决!
使用分段发送和分段接收,问题已经解决!
前面说的 CAsyncSocket类没有通知OnReceive()消息 的问题其实是客户端发送数据过长,需要几分钟后才能收到数据,误以为是没有返回,现在已经解决了。再次感谢shenyi0106

#9


一般TCP/UDP通信, 都是需要组包拆包的.

如果接收的数据不够1个包长, 就需要继续等待下一次接收, 拼接起来
够一个包长或者多个包长, 就需要拆包.

#1


代码加了很多注释了,希望能看懂!

#2


为了更好的发现问题所在,我把发送数据的代码也贴上来吧
int CMySocket::SendData(int msgid,char *buff, size_t buffsize)//参数分别是消息ID,发送的数据,发送数据的大小
{
char *sendbuff=NULL;
int ret=0,count=0;
sendbuff = (char*)malloc(buffsize+sizeof(msgid)+sizeof(buffsize));
memcpy(sendbuff,&msgid,sizeof(msgid));
memcpy(sendbuff+sizeof(msgid),&buffsize,sizeof(buffsize));
memcpy(sendbuff+sizeof(msgid)+sizeof(buffsize),buff,buffsize);

 //以下是发送的主要代码---------------------------------------------------------------------------
ret = Send(sendbuff,buffsize+sizeof(buffsize)+sizeof(msgid));

int sendsize = buffsize+sizeof(buffsize)+sizeof(msgid);
for (int sendpos=ret; sendpos < sendsize; sendpos += ret)
{
ret = Send(sendbuff+sendpos,sendsize-sendpos);
Sleep(1);
}
free(sendbuff);//释放buff
//----------------------------------------------------------------------------------------------------------
return ret;
}

#3


ret = asyncSocket->Receive(str,sizeof(msgid)+sizeof(datasize));

这句代码不一定能够返回你想要收到的数据长度,你应该循环收取,直到满足你的长度要求为止:

char szBuf[8192[;
char *pos= szBuf;
int nIndex = 0;
int nRecvLen= sizeof(msgid) + sizeof(datasize);

while (1)
{
     int len = asyncSocket->Receive(pos+ nIndex,  nRecvLen - nIndex);
     if (len <= 0)
     {
             TRACE("Receive Error: %ld\n", WSAGetLastError());
             break;
     }

     nIndex += len;
     if (nIndex == nRecvLen ) 
     {
           break;
     }
}

// 
//  你的数据处理代码

#4


引用 3 楼 shenyi0106 的回复:
ret = asyncSocket->Receive(str,sizeof(msgid)+sizeof(datasize));

这句代码不一定能够返回你想要收到的数据长度,你应该循环收取,直到满足你的长度要求为止:

char szBuf[8192[;
char *pos= szBuf;
int nIndex = 0;
int nRecvLen= sizeof(msgid) + sizeof(datasize);

while (1)
{
     int len = asyncSocket->Receive(pos+ nIndex,  nRecvLen - nIndex);
     if (len <= 0)
     {
             TRACE("Receive Error: %ld\n", WSAGetLastError());
             break;
     }

     nIndex += len;
     if (nIndex == nRecvLen ) 
     {
           break;
     }
}

// 
//  你的数据处理代码

谢谢!请问在消息机制下可以这样接收数据吗?

#5


引用 4 楼 qq1412198766 的回复:
Quote: 引用 3 楼 shenyi0106 的回复:

ret = asyncSocket->Receive(str,sizeof(msgid)+sizeof(datasize));

这句代码不一定能够返回你想要收到的数据长度,你应该循环收取,直到满足你的长度要求为止:

char szBuf[8192[;
char *pos= szBuf;
int nIndex = 0;
int nRecvLen= sizeof(msgid) + sizeof(datasize);

while (1)
{
     int len = asyncSocket->Receive(pos+ nIndex,  nRecvLen - nIndex);
     if (len <= 0)
     {
             TRACE("Receive Error: %ld\n", WSAGetLastError());
             break;
     }

     nIndex += len;
     if (nIndex == nRecvLen ) 
     {
           break;
     }
}

// 
//  你的数据处理代码

谢谢!请问在消息机制下可以这样接收数据吗?

可以,而且必须要这样收

#6


引用 5 楼 shenyi0106 的回复:
Quote: 引用 4 楼 qq1412198766 的回复:

Quote: 引用 3 楼 shenyi0106 的回复:

ret = asyncSocket->Receive(str,sizeof(msgid)+sizeof(datasize));

这句代码不一定能够返回你想要收到的数据长度,你应该循环收取,直到满足你的长度要求为止:

char szBuf[8192[;
char *pos= szBuf;
int nIndex = 0;
int nRecvLen= sizeof(msgid) + sizeof(datasize);

while (1)
{
     int len = asyncSocket->Receive(pos+ nIndex,  nRecvLen - nIndex);
     if (len <= 0)
     {
             TRACE("Receive Error: %ld\n", WSAGetLastError());
             break;
     }

     nIndex += len;
     if (nIndex == nRecvLen ) 
     {
           break;
     }
}

// 
//  你的数据处理代码

谢谢!请问在消息机制下可以这样接收数据吗?

可以,而且必须要这样收

谢谢!可是我又发现一个问题,可能是问题的关键所在:
int len = asyncSocket->Receive(pos+ nIndex,  nRecvLen - nIndex);
当这一句接受数据量太大的话,这句是否会导致socket缓冲区溢出?我记得socket的缓冲区好像是固定大小的,溢出之后CAsyncSocket类的OnReceive()消息是否就再也收不到了?

#7


socket缓冲区溢出的可能性已经排除,现在问题还是没有解决,现在的问题主要如下:

1、服务端能发送数据。
2、客户端接收服务端的数据成功,发送也成功。
3、服务端没能收到客户端发送的数据,CAsyncSocket类并没有通知OnReceive()消息有数据接收。

问题就是出现在第3步,CAsyncSocket类没有通知OnReceive()消息。可是这个问题又是怎么触发出来的?纳闷中。。
大神们求解。。

#8


非常感谢:shenyi0106
问题已经解决!
使用分段发送和分段接收,问题已经解决!
前面说的 CAsyncSocket类没有通知OnReceive()消息 的问题其实是客户端发送数据过长,需要几分钟后才能收到数据,误以为是没有返回,现在已经解决了。再次感谢shenyi0106

#9


一般TCP/UDP通信, 都是需要组包拆包的.

如果接收的数据不够1个包长, 就需要继续等待下一次接收, 拼接起来
够一个包长或者多个包长, 就需要拆包.