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中的全部客户端。
相关代码:

  1. DWORD WINAPI CServer::worker_thread(LPVOID server)
  2. {
  3. CServer* m_server=(CServer*)server;
  4. DWORD bytes=0;
  5. overlapped_wrapper* over_type;
  6. BOOL close_socket = false;
  7. DWORD last_error =0;
  8. BOOL ret;
  9. while (true)
  10. {
  11. SOCKET socket;
  12. ret = GetQueuedCompletionStatus(m_server->completion_port_, &bytes,(LPDWORD)&socket, (LPOVERLAPPED *) &over_type, INFINITE);
  13. if(ret == ERROR_SUCCESS)
  14. {
  15. DWORD last_error = GetLastError();
  16. if(ERROR_INVALID_HANDLE == last_error)
  17. {
  18. ConsoleOutput("Completion port be erro quit! GetLastErro:%d\n",GetLastError());
  19. return 0;
  20. }
  21. else if(ERROR_NETNAME_DELETED == last_error|| ERROR_OPERATION_ABORTED == last_error)
  22. {
  23. //ConsoleOutput("socket be closed or operation be cancled.GetLastErro:%d\n",GetLastError());
  24. close_socket = true;
  25. }
  26. else
  27. {
  28. ConsoleOutput("GetQueuedCompletionStatus erro! GetLastErro:%d\n",GetLastError());
  29. continue;
  30. }
  31. }
  32. //quit
  33. else if(bytes == 0 && socket == 0 && over_type == NULL)
  34. {
  35. ConsoleOutput("GetQueuedCompletionStatus be normal quit. GetLastErro:%d\n",GetLastError());
  36. return 0;
  37. }
  38. assert(over_type);
  39. switch(over_type->io_type)
  40. {
  41. case IO_EVENT_ACCEPT:
  42. {
  43. acceptex_block* a_block = (acceptex_block*)over_type;

  44. //1.accept failed ,then post a new accept request.
  45. //2.accept success,then post a new accept request.
  46. if(close_socket)
  47. {
  48. m_server->on_tcp_listen_close(a_block);
  49. }
  50. else
  51. {
  52. m_server->on_acceptex(a_block);
  53. }
  54. }
  55. break;
  56. case IO_EVENT_WSARECV:
  57. {
  58. recv_block* r_block = (recv_block*)over_type;
  59. //closed
  60. if (close_socket || bytes == 0 || bytes == -1)
  61. {
  62. //try one time,confirm it was true closed.
  63. char test_close;
  64. int r = 0;//recv(r_block->socket, &test_close, sizeof(test_close), MSG_PEEK);
  65. if(r == 0 || r == SOCKET_ERROR)
  66. {
  67. m_server->on_tcp_close((data_block*)r_block);
  68. }
  69. }
  70. //recved data
  71. else
  72. {
  73. //process data
  74. r_block->bytes_recveived += bytes;
  75. m_server->on_recv(r_block);
  76. }
  77. }
  78. break;
  79. case IO_EVENT_WSASEND:
  80. {
  81. send_block* s_block = (send_block*)over_type;
  82. //closed
  83. if (close_socket || bytes == 0 || bytes == -1)
  84. {
  85. //try one time,confirm it was true closed.
  86. char test_close;
  87. int r = 0;//send(s_block->socket, &test_close, sizeof(test_close), MSG_PEEK);
  88. if(r == 0 || r == SOCKET_ERROR)
  89. {
  90. m_server->on_tcp_close((data_block*)s_block);
  91. }
  92. }
  93. //send data
  94. else
  95. {
  96. //process data
  97. s_block->bytes_sended += bytes;
  98. m_server->on_send(s_block);
  99. }
  100. }
  101. break;
  102. default:
  103. ConsoleOutput("worker thread default break;");
  104. break;
  105. }
  106. close_socket=false;
  107. last_error=0;
  108. }
  109. return 0;
  110. }

...全文
给本帖投票
1188 15 打赏 收藏 转发到动态 举报
AI 作业
写回复
用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创作助手写篇文章吧

手机看
关注公众号

关注公众号

客服 返回
顶部