为什么WSAWaitForMultipleEvents函数没有接收到数据?

hattah 2009-02-19 10:02:08
主啊,救救我吧.搞了N天了,可还是不知道为什么WSAWaitForMultipleEvents参数里的事件就是没有受信啊.用sniffer抓包,发现数据已经发过来了.可为什么我的客户端程序就是没有响应.下面是我程序代码.先谢谢大家了.我帮解决这个问题吧.
DWORD WINAPI CP2PClient::RecvThreadProcFromServer(LPVOID lpParam){
CP2PClient * client = (CP2PClient*)lpParam;
while(TRUE)
{
if(client->m_bThreadServerExit)
break;
// 在所有事件对象上等待
int nIndex = ::WSAWaitForMultipleEvents(client->nEventTotal, client->eventArray, FALSE, WSA_INFINITE, FALSE);
// 对每个事件调用WSAWaitForMultipleEvents函数,以便确定它的状态
nIndex = nIndex - WSA_WAIT_EVENT_0;
for(int i=nIndex; i<client->nEventTotal; i++)
{
nIndex = ::WSAWaitForMultipleEvents(1, &client->eventArray[i], TRUE, 1000, FALSE);
if(nIndex == WSA_WAIT_FAILED || nIndex == WSA_WAIT_TIMEOUT)
{
continue;
}
else
{
// 获取到来的通知消息,WSAEnumNetworkEvents函数会自动重置受信事件

WSANETWORKEVENTS event;
::WSAEnumNetworkEvents(client->sockArray[i], client->eventArray[i], &event);
if(event.lNetworkEvents & FD_ACCEPT) // 处理FD_ACCEPT通知消息
{
if(event.iErrorCode[FD_ACCEPT_BIT] == 0)
{
if(client->nEventTotal > WSA_MAXIMUM_WAIT_EVENTS)
{
printf(" Too many connections! \n");
continue;
}
SOCKET sNew = ::accept(client->sockArray[i], NULL, NULL);
WSAEVENT event = ::WSACreateEvent();
::WSAEventSelect(sNew, event, FD_READ|FD_CLOSE|FD_WRITE);
// 添加到表中
client->eventArray[client->nEventTotal] = event;
client->sockArray[client->nEventTotal] = sNew;
client->nEventTotal++;
}
}
else if(event.lNetworkEvents & FD_READ) // 处理FD_READ通知消息
{
if(event.iErrorCode[FD_READ_BIT] == 0)
{
char szText[1024];
// CP2PMessage *pMsg;
int nRecv = ::recv(client->sockArray[i], szText, strlen(szText), 0);

// if(nRecv > 0)
{
szText[nRecv] = '\0';
// pMsg = (CP2PMessage *)szText;
client->HandleIOFromServer(szText,nRecv);
//printf("接收到数据:%s \n", szText);
}
}

}
else if(event.lNetworkEvents & FD_CLOSE) // 处理FD_CLOSE通知消息
{
if(event.iErrorCode[FD_CLOSE_BIT] == 0)
{
::closesocket(client->sockArray[i]);
for(int j=i; j<client->nEventTotal-1; j++)
{
client->sockArray[j] = client->sockArray[j+1];
client->sockArray[j] = client->sockArray[j+1];
}
client->nEventTotal--;
}
}
else if(event.lNetworkEvents & FD_WRITE) // 处理FD_WRITE通知消息
{

}
::WSAResetEvent(client->eventArray[i]);
}
}
}
return 0;
}
...全文
313 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
wuwenxi 2009-07-10
  • 打赏
  • 举报
回复
我和你发生了一个类是的状况,你的WSAWaitForMultipleEvents的第一个参数应该是当前连接到服务器的实际客户端数量,而不是能够连接的最大数量
花花呀123456 2009-05-30
  • 打赏
  • 举报
回复
直接返回时因为 你的函数调用WSAWaitForMultipleEvents没有成功,我的也是函数返回值为NULL,可以调用WSAGetLastError看看,到底是什么错误,我的也是这样,后面发现错误代码为6,也就是 句柄无效。
hattah 2009-02-19
  • 打赏
  • 举报
回复
不是nEventTotal 的原因,这个肯定没问题的.我的初始值nEventTotal =0 ;eventArray[nEventTotal] = event后做了一次nEventTotal++;
大哥有没有这方面的程序,要不发一个到我邮箱plane539@163.com.不胜感激啊!
a_rockboy 2009-02-19
  • 打赏
  • 举报
回复
eventArray[nEventTotal] = event;

client->nEventTotal, client->eventArray

你的nEventTotal = 1?
eventArray[nEventTotal] = event; 好像不对eventArray[nEventTotal - 1] = event
hattah 2009-02-19
  • 打赏
  • 举报
回复
WSAEVENT event = ::WSACreateEvent();
eventArray[nEventTotal] = event;
这样创建的

程序一直循环就是说

程序并没有在int nIndex = ::WSAWaitForMultipleEvents(client->nEventTotal, client->eventArray, FALSE, WSA_INFINITE, FALSE); 这一行停下来,等待事件对象被激活.而是每次到这都能执行下去.
你不是说WSAEnumNetworkEvents函数能让事件对象处理reset的状态吗!但我这好像事件对象根本就没有被WSAEnumNetworkEvents函数reset.每次到int nIndex = ::WSAWaitForMultipleEvents(client->nEventTotal, client->eventArray, FALSE, WSA_INFINITE, FALSE); 这一行都直接就运行下去了!
但接收到的数据却又是长度为0的.服务器那边明显已经发过数据来了.sniffer已经抓到了!
caitian6 2009-02-19
  • 打赏
  • 举报
回复
程序一直循环,每次都会进到读事件里.而且收到的长度都为0?
client->eventArray 事件是怎么创建的?有没有创建成功
参考下面的代码
if ((EventArray[0] = ListenOverlapped.hEvent = WSACreateEvent()) == WSA_INVALID_EVENT)
{
printf("WSACreateEvent failed with error %d\n", WSAGetLastError());
return;
}
hattah 2009-02-19
  • 打赏
  • 举报
回复
可是我不手动设置事件为无信号,程序就在不停的循环.根本不会在WSAWaitForMultipleEvents停下来等待
client->eventArray里其实就1个事件对象,而且这里只有读事件
程序一直循环,每次都会进到读事件里.而且收到的长度都为0,但我的服务器没发长度为0数据过来啊.发过来的数据,下面的代码也接收不到!
求大虾赐教啊,快崩溃了!
while(TRUE)
{
if(client->m_bThreadServerExit)
break;
// 在所有事件对象上等待
int nIndex = ::WSAWaitForMultipleEvents(client->nEventTotal, client->eventArray, FALSE, WSA_INFINITE, FALSE);
// 对每个事件调用WSAWaitForMultipleEvents函数,以便确定它的状态

switch(nIndex)
{
case WAIT_OBJECT_0: //第一个事件触发
WSANETWORKEVENTS event;
::WSAEnumNetworkEvents(client->sockArray[0], client->eventArray[0], &event);
if(event.lNetworkEvents & FD_ACCEPT) // 处理FD_ACCEPT通知消息
{
if(event.iErrorCode[FD_ACCEPT_BIT] == 0)
{
if(client->nEventTotal > WSA_MAXIMUM_WAIT_EVENTS)
{
printf(" Too many connections! \n");
continue;
}
SOCKET sNew = ::accept(client->sockArray[0], NULL, NULL);
WSAEVENT event = ::WSACreateEvent();
::WSAEventSelect(sNew, event, FD_READ|FD_CLOSE|FD_WRITE);
// 添加到表中
client->eventArray[client->nEventTotal] = event;
client->sockArray[client->nEventTotal] = sNew;
client->nEventTotal++;
}
}
else if(event.lNetworkEvents & FD_READ) // 处理FD_READ通知消息
{
if(event.iErrorCode[FD_READ_BIT] == 0)
{
char szText[1024] = {0};
int nRecv = ::recv(client->sockArray[0], szText, strlen(szText), 0);
{
szText[nRecv] = '\0';
client->HandleIOFromServer(szText,nRecv);
}
}

}
else if(event.lNetworkEvents & FD_CLOSE) // 处理FD_CLOSE通知消息
{
if(event.iErrorCode[FD_CLOSE_BIT] == 0)
{
::closesocket(client->sockArray[0]);
for(int j=0; j<client->nEventTotal-1; j++)
{
client->sockArray[j] = client->sockArray[j+1];
client->sockArray[j] = client->sockArray[j+1];
}
client->nEventTotal--;
}
}
else if(event.lNetworkEvents & FD_WRITE) // 处理FD_WRITE通知消息
{

}

continue;
case WAIT_OBJECT_0 + 1: //第二个事件触发
continue;
// case WAIT_OBJECT_0 + n - 1: //第n个事件触发
// break;
case WSA_WAIT_FAILED:
continue;
case WSA_WAIT_TIMEOUT:
continue;
}

}
caitian6 2009-02-19
  • 打赏
  • 举报
回复
WSAWaitForMultipleEvents 等待有信号的事件, 返回的事件ID ,肯定是有信号的.
为了循环等待,必须把WSAWaitForMultipleEvents 返回的事件ID, 手动置为无信号的, 也就是WSAResetEvent。
但WSAEnumNetworkEvents 可以相当于WSAResetEvent
hattah 2009-02-19
  • 打赏
  • 举报
回复
哈哈,多谢兄弟们关心,算法是书上写的.说如果指明的对象总有网络事件发生,那么后面其他事件对象所关联的网络事件就得不到处理了,解决办法是,WSAWaitForMultipleEvents函数返回后,对每个事件都再次调用WSAWaitForMultipleEvents函数,以便确定其状态.

还有一点不明白的是,调用了WSAWaitForMultipleEvents函数后,事件参数lphEvent是什么状态,是受信还是非受信?

要不要再调用WSAResetEvent函数将事件对象重新设置状态?

谢谢大家了!
caitian6 2009-02-19
  • 打赏
  • 举报
回复
你怎么调用两次WSAWaitForMultipleEvents ?
调用一次就OK
a_rockboy 2009-02-19
  • 打赏
  • 举报
回复
int nIndex = ::WSAWaitForMultipleEvents(client->nEventTotal, client->eventArray, FALSE, WSA_INFINITE, FALSE);
// 对每个事件调用WSAWaitForMultipleEvents函数,以便确定它的状态
nIndex = nIndex - WSA_WAIT_EVENT_0;
for(int i=nIndex; i <client->nEventTotal; i++)
{
nIndex = ::WSAWaitForMultipleEvents(1, &client->eventArray[i], TRUE, 1000, FALSE);
if(nIndex == WSA_WAIT_FAILED || nIndex == WSA_WAIT_TIMEOUT)
{
continue;
}

这啥用法啊。

都是这么用
int nIndex = ::WSAWaitForMultipleEvents(client->nEventTotal, client->eventArray, FALSE,
WSA_INFINITE, FALSE);

switch(nIndex)
{
case WAIT_OBJECT_0: //第一个事件触发
DoSomeThing;
break;
case WAIT_OBJECT_0 + 1: 第二个事件触发
DoSomeThing;
break
...
case WAIT_OBJECT_0 + n - 1: 第n个事件触发
DoSomeThing;
break;
case WSA_WAIT_FAILED:
case WSA_WAIT_TIMEOUT:
DoSomeThing;
break;
}
hattah 2009-02-19
  • 打赏
  • 举报
回复
在程序开始也没有交代创建的事件对象关联到什么套接字, 而且更重要的是没说明注册的是什么类型的事件.

这些当然都做了.

奇怪的是.登陆的时候没问题.服务器返回客户登陆也没问题,客户再向服务器发送请求用户列表也没问题.

然后服务器将用户列表发回来,客户端就什么也收不到,再也没反应了.
a_rockboy 2009-02-19
  • 打赏
  • 举报
回复
if(event.lNetworkEvents & FD_ACCEPT) // 处理FD_ACCEPT通知消息

没见过这么使用的。

WSAAsyncSelect():要求某一 Socket 有事件 (event) 发生时通知使用者。
格 式: int PASCAL FAR WSAAsyncSelect( SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent );
参 数: s Socket 的编号
hWnd 动作完成後,接受讯息的视窗 handle
wMsg 传回视窗的讯息
lEvent 应用程式有兴趣的网路事件
传回值: 成功 - 0
失败 - SOCKET_ERROR (呼叫 WSAGetLastError() 可得知原因)
说明: 此函式是让使用者用来要求 Windows Sockets DLL 在侦测到某一Socket有网路事件时送讯息到使用者指定的视窗;网路事件是由参数 lEvent 设定。呼叫此函式会主动将该 Socket 设定为 Non-blocking 模式。lEvent 的值可为以下之「OR」

组合:(参见 WINSOCK第1.1版88、89页) FD_READ、FD_WRITE、FD_OOB、FD_ACCEPT、FD_CONNECT、FD_CLOSE使用者若是针对某一Socket再次呼叫此函式时,会取消对该 Socket 原先之设定。若要取消对该Socket 的所有设定,则lEvent 的值必须设为 0。

在hWnd窗口的wMsg事件处理中,使用WSAGETSELECTEVENT(lParam)取得当前发生的事件
dong364 2009-02-19
  • 打赏
  • 举报
回复
你没有搞清楚你这是客户端程序吗? 竟然还有 处理FD_ACCEPT通知消息 的选择分支? 在程序开始也没有交代创建的事件对象关联到什么套接字, 而且更重要的是没说明注册的是什么类型的事件.
hattah 2009-02-19
  • 打赏
  • 举报
回复
好的,谢谢啦

你觉得为什么事件对象没有受信呢?有什么可能导致他没受信?

sniffer已经抓到发过来的正确数据,就是说已经到client端的网卡了,怎么然后就不会通知程序的socket呢?
caitian6 2009-02-19
  • 打赏
  • 举报
回复
你可以参考 Windows网络编程技术 第八章, 对 AnySelect 有详细的讲解

18,356

社区成员

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

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