非阻塞的socket为什么发送和接收的数据不一致?

ClassDan 2010-08-11 11:26:03
基于TCP的远程算术程序,使用非阻塞socket。

//服务器发送线程
DWORD WINAPI CClient::SendThread(void *pParam)
{
CClient *pClient=(CClient *)pParam;

while(pClient->m_isConnected)
{
if(WAIT_OBJECT_0==WaitForSingleObject(pClient->m_hSendEvent,INFINITE)) //等待发送事件
{
if(!pClient->m_isConnected) //如果连接断开
{
pClient->m_isConnected=false;
break;
}

int retval=send(pClient->m_socket,pClient->m_sendData.buf,((pHdr)pClient->m_sendData.buf)->len,0);

if(retval==SOCKET_ERROR) //发送失败
{
int ErrCode=WSAGetLastError();
if(ErrCode==WSAEWOULDBLOCK)
continue;
else if(ErrCode==WSAENETDOWN || ErrCode==WSAECONNRESET || ErrCode==WSAETIMEDOUT)
{
pClient->m_isConnected=false;
pClient->m_isExit=true;
break;
}
}

ResetEvent(pClient->m_hSendEvent); //重置发送事件
}
}

return 0;
}


//客户端接收线程
DWORD WINAPI RecvThread(void *pParam)
{
char temp[MAX_BUF_SIZE]; //临时接收缓冲区
memset(temp,0,MAX_BUF_SIZE);
int ival;

while(g_isConnected)
{
ival=recv(g_sClient,temp,MAX_BUF_SIZE,0);
if(ival==SOCKET_ERROR) //接收失败
{
int ErrCode=WSAGetLastError();
if(ErrCode==WSAEWOULDBLOCK)
{
Sleep(500);
continue;
}
else
{
g_isConnected=false;
SetEvent(g_hShowResultEvent);
break;
}
}
else if(ival==0) //连接关闭
{
g_isConnected=false;
SetEvent(g_hShowResultEvent);
break;
}
else if(ival>HEADERLEN) //接收成功
{
//将接收到的数据解包并拷贝到全局的接收缓冲区中
pHdr pHeader=(pHdr)temp;
memset(g_RecvBuf.buf,0,MAX_BUF_SIZE);
memcpy(g_RecvBuf.buf,temp+HEADERLEN,pHeader->len-HEADERLEN);

SetEvent(g_hShowResultEvent); //通知显示计算结果
}

memset(temp,0,MAX_BUF_SIZE);
Sleep(500);
}

SetEvent(g_hSendEvent); //线程退出时设置发送事件为有信号状态,以防发送线程一直等待

return 0;
}

测试远程计算1+1=?
问题:经调试发现,服务器发送线程发送的数据包是正确的,其中包头内类型字段值为“E”(算术表达式),长度(包头+数据的总长度)字段为13,包体的数据为“1+1=2”。
而客户端接收到的数据包却完全不一样,调试得知接收到的数据包包头内类型字段值为“D”(未定义这种类型),长度字段为2734738122,包体的数据为“g◆弨螮”。并且接收到的数据长度为29字节,不是发送的13字节!
请问这是什么原因?
...全文
489 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
carlolin 2010-08-17
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 buptzwp 的回复:]
引用 3 楼 carlolin 的回复:

可能发丢包了 用SELECT模型判断一下缓冲区是否可写

丢包,TCP不至于把。
[/Quote]
发大数据量的时候缓冲区满了写不进去了 就丢包了呗
云瑀 2010-08-11
  • 打赏
  • 举报
回复
1.把receive/send buffer加长
2.定义好讯息格式,用多次接收然后解析讯息的方式处理(长度判断,或结尾字串都可)
lazy_2010 2010-08-11
  • 打赏
  • 举报
回复
接收数据的时候,可能需要多次接收才能收到完整数据
buptzwp 2010-08-11
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 carlolin 的回复:]

可能发丢包了 用SELECT模型判断一下缓冲区是否可写
[/Quote]
丢包,TCP不至于把。
carlolin 2010-08-11
  • 打赏
  • 举报
回复
可能发丢包了 用SELECT模型判断一下缓冲区是否可写
Eleven 2010-08-11
  • 打赏
  • 举报
回复
看看send和recv的返回值是多少?正确吗?
hurryboylqs 2010-08-11
  • 打赏
  • 举报
回复
发送和接收检验收到长度 不单单判断是否出错了事
mudunke775 2010-08-11
  • 打赏
  • 举报
回复
应该是抓包工具抓到你的包后在包的前面加个一些数据,可能认为你的程序是非法的,所以才加的数据,而QQ等工具是默认为合法数据,抓到后不做修改。

你可以写个其他的程序发送试试。
ClassDan 2010-08-11
  • 打赏
  • 举报
回复
终于发现问题所在了!
我跟踪调试Client程序,发现接收到的数据开头都是“Drcom...(后面还有一段乱码)”,直到第18个字节开始才是正常发送的数据(包头类型“E”,包头长度13,数据“1+1=2”)。想到“Drcom”这些字符与学校上网认证客户端名字Dr.com一样,是不是接收了Dr.com的数据了?马上关掉Dr.com,重新测试服务器和客户端,一切正确。

但是又有了一个疑问,为什么Dr.com会影响我的程序呢?好像Dr.com安装时还附带安装了一个抓包的工具WinPcap,可能是它把网卡设为了“混杂模式”导致的,但是怎么其他的软件(如QQ)就不受影响呢?
ClassDan 2010-08-11
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 cloudhsu 的回复:]

1.把receive/send buffer加长
2.定义好讯息格式,用多次接收然后解析讯息的方式处理(长度判断,或结尾字串都可)
[/Quote]
这个跟buffer长度没关系吧?我定义的发送和接收buffer都远大于实际数据包大小(buffer大小为48,而一般正常的算术表达式在10-30之间)
ClassDan 2010-08-11
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 visualeleven 的回复:]

看看send和recv的返回值是多少?正确吗?
[/Quote]
send的返回值是13,recv的返回值是29。

18,356

社区成员

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

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