iocp中GetQueuedCompletionStatus的问题?

msspy 2011-09-07 02:03:39
现象:GetQueuedCompletionStatus 返回后,GetLastError = 121 (信号灯超时时间已到),出现这个提示后,服务程序变卡,客户端不能流畅的接收数据;没有这个错误则客户端接收流畅。
目的:tcp协议做一个消息广播服务器,客户端数量在5000左右,且并发500条信息的几率大,服务器收到一条新信息,就对其他所有在线客户端广播一遍。
实现思路:在accept时,保存了一个全局的队列,记录当前在线的客户端数量csafemap<SOCKET>client_list,然后iocp实现中接收每个客户端上传的信息并存入数据库;另外新建了一个线程,每隔5秒读取一次数据库,读本次间隔内收到的信息,然后把这些信息while循环发给client_list中的全部客户端。
相关代码:

DWORD WINAPI CServer::worker_thread(LPVOID server)
{
CServer* m_server=(CServer*)server;
DWORD bytes=0;
overlapped_wrapper* over_type;
BOOL close_socket = false;
DWORD last_error =0;
BOOL ret;
while (true)
{
SOCKET socket;
ret = GetQueuedCompletionStatus(m_server->completion_port_, &bytes,(LPDWORD)&socket, (LPOVERLAPPED *) &over_type, INFINITE);
if(ret == ERROR_SUCCESS)
{
DWORD last_error = GetLastError();
if(ERROR_INVALID_HANDLE == last_error)
{
ConsoleOutput("Completion port be erro quit! GetLastErro:%d\n",GetLastError());
return 0;
}
else if(ERROR_NETNAME_DELETED == last_error|| ERROR_OPERATION_ABORTED == last_error)
{
//ConsoleOutput("socket be closed or operation be cancled.GetLastErro:%d\n",GetLastError());
close_socket = true;
}
else
{
ConsoleOutput("GetQueuedCompletionStatus erro! GetLastErro:%d\n",GetLastError());
continue;
}
}
//quit
else if(bytes == 0 && socket == 0 && over_type == NULL)
{
ConsoleOutput("GetQueuedCompletionStatus be normal quit. GetLastErro:%d\n",GetLastError());
return 0;
}
assert(over_type);
switch(over_type->io_type)
{
case IO_EVENT_ACCEPT:
{
acceptex_block* a_block = (acceptex_block*)over_type;

//1.accept failed ,then post a new accept request.
//2.accept success,then post a new accept request.
if(close_socket)
{
m_server->on_tcp_listen_close(a_block);
}
else
{
m_server->on_acceptex(a_block);
}
}
break;
case IO_EVENT_WSARECV:
{
recv_block* r_block = (recv_block*)over_type;
//closed
if (close_socket || bytes == 0 || bytes == -1)
{
//try one time,confirm it was true closed.
char test_close;
int r = 0;//recv(r_block->socket, &test_close, sizeof(test_close), MSG_PEEK);
if(r == 0 || r == SOCKET_ERROR)
{
m_server->on_tcp_close((data_block*)r_block);
}
}
//recved data
else
{
//process data
r_block->bytes_recveived += bytes;
m_server->on_recv(r_block);
}
}
break;
case IO_EVENT_WSASEND:
{
send_block* s_block = (send_block*)over_type;
//closed
if (close_socket || bytes == 0 || bytes == -1)
{
//try one time,confirm it was true closed.
char test_close;
int r = 0;//send(s_block->socket, &test_close, sizeof(test_close), MSG_PEEK);
if(r == 0 || r == SOCKET_ERROR)
{
m_server->on_tcp_close((data_block*)s_block);
}
}
//send data
else
{
//process data
s_block->bytes_sended += bytes;
m_server->on_send(s_block);
}
}
break;
default:
ConsoleOutput("worker thread default break;");
break;
}
close_socket=false;
last_error=0;
}
return 0;
}

...全文
1160 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
msspy 2011-09-19
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 chenjiawei007 的回复:]
你有几个工作线程?出现121问题的时候,是在客户端并发连接CONNECT的时候,还是在进行数据SEND的时候?121是信号量超时,你检查下用到event的地方。从你描述的问题和发的代码上看不出问题。还有先把数据接受和数据处理的逻辑先分开来,这很影响性能。
[/Quote]
是分开的,用任务池分开的,发现数据后,将数据投递给任务池,有任务池去完成逻辑业务。
postmessage出去的。
smwhotjay 2011-09-09
  • 打赏
  • 举报
回复
styleman_iocp当然有例子. echo.

关于报毒.那是我把styleman_iocp.dll加壳了.防止无聊人员爆破. 360就把我那几个引擎给报毒了.
msspy 2011-09-09
  • 打赏
  • 举报
回复
再顶,等神人出现。。。
chenjiawei007 2011-09-09
  • 打赏
  • 举报
回复
你有几个工作线程?出现121问题的时候,是在客户端并发连接CONNECT的时候,还是在进行数据SEND的时候?121是信号量超时,你检查下用到event的地方。从你描述的问题和发的代码上看不出问题。还有先把数据接受和数据处理的逻辑先分开来,这很影响性能。
msspy 2011-09-08
  • 打赏
  • 举报
回复
现在修改了方案:
去掉了客户端队列client_list及单线程循环广播,改成客户端发送获取新消息的命令,服务端收到命令,返回新消息(可能是几百条数据,每个数据是300字节左右),现在出现121的几率降低了,但是还是偶尔出现。
msspy 2011-09-08
  • 打赏
  • 举报
回复
老大有例子吗?
[Quote=引用 5 楼 smwhotjay 的回复:]
客户端数量在5000左右,且并发500条信息

看平均每信息多少字节.

几百字节的话.可以用我封装好的styleman_iocp 单iocp可以连接1000客户.同时并发1KB/S收发. 所以可以
2000连接 500字节收发/S.

iocp要封装好不容易.考验程序员的编程水平和对win系统的认识.
[/Quote]
hurryboylqs 2011-09-07
  • 打赏
  • 举报
回复
建议你用boost的 asio
牛逼的,你都不用去管什么IOCP而且是跨平台的

在windows下Boost的asio就是用IOCP实现的,但你不需要
去了解太多细节,而专注于自己的应用逻辑处理。
chenjiawei007 2011-09-07
  • 打赏
  • 举报
回复
LS几位说到了,
服务器要做好,有两个问题要关注

1.数据压缩,解压。

2.数据流的存放,尽可能减少队列来避免同步竞争。
架构师Wu老七 2011-09-07
  • 打赏
  • 举报
回复
Eleven 说的很有道理, 厉害..
Eleven 2011-09-07
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 shenyi0106 的回复:]
将接收数据和处理数据的的逻辑分开
让工作者线程专注于网络IO
[/Quote]
同意,最好分开模块化,否则盖起来很麻烦,接收数据的模块只负责接收数据,不负责处理。可以专门开个线程去处理数据,接收数据模块收到数据以后就将数据投递到处理线程。线程比较多的话可以考虑使用内存池线程池方案
smwhotjay 2011-09-07
  • 打赏
  • 举报
回复
客户端数量在5000左右,且并发500条信息

看平均每信息多少字节.

几百字节的话.可以用我封装好的styleman_iocp 单iocp可以连接1000客户.同时并发1KB/S收发. 所以可以
2000连接 500字节收发/S.

iocp要封装好不容易.考验程序员的编程水平和对win系统的认识.
尘雨 2011-09-07
  • 打赏
  • 举报
回复
建议用两个进程,一个进程用于接收客户端消息,另外一个进程用于给客户端广播消息。两个进程之间的通信处理好就行了。这样做在收转会有一定的延迟。但稳定性会更好一些。仅仅是个思路
huanglei2 2011-09-07
  • 打赏
  • 举报
回复
这么复杂 关注!
shenyi0106 2011-09-07
  • 打赏
  • 举报
回复
将接收数据和处理数据的的逻辑分开
让工作者线程专注于网络IO
msspy 2011-09-07
  • 打赏
  • 举报
回复
备注:
这个问题在客户端数量较多时,非常容易出现。
服务端在给客户端广播信息时,客户端如果再频繁发送新信息,肯定出现这个现象。

18,363

社区成员

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

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