使用IOCP时怪异现象-多连接状态异常

IOCP多连接管理基本模型

server端IOCP多连接管理基本模型如下:
1)启动一个接受线程,用于接受client发起的连接请求;
2)创建一个IOCP(I/O complete port)和一组工作线程;当client发起连接请求时,接受线程将client socket绑定到IOCP上;工作线程负责对这些client socket的收/发完成消息进行响应,同时也发起收/发请求,或者说工作线程负责实现client socket的通信过程;

连接状态

TCP连接是全双工通信,收/发是独立的,因此状态包括idle, sending, receiving三种。

服务端通信过程

当一个client连接到服务端之后,服务端处理过程如下:
1)发起接受请求,该clien 处于receiving状态
2)处理接收报文,如果接受报文是数据请求数据包,则组织数据报文,然后将数据报文发送出去,client更新为sending状态。否则状态不变,继续等待接收事件。
3)处理发送完成事件,数据发送完成后转入步骤1,否则状态不变。

现象

1)多工作线程下,单条client很容易出现假死状态(对接收数据无响应)
2)单个工作线程下,单条和多条client运行正常

分析原因

有上面现象可以分析出一定与多个工作线程有关,但很想知道这种情况是怎么出现的。于是在代码中添加了一些调试信息:在每次client状态改变时,打印线程ID,client的Socket,新状态值。

代码

unsigned __stdcall thread_processcomm(void* p_param)
{
	struct s_tcpsrv_context *p_ctx = (struct s_tcpsrv_context*)p_param;
	c_tcpserver *p_server = (c_tcpserver*)p_ctx->p_tcpsrv;
	unsigned ui_iocpidx = p_ctx->ui_iocpidx;
	assert(NULL != p_server);
	HANDLE hdl_iocp = (HANDLE)p_server->hdl_iocps[ui_iocpidx];
	c_protocol* p_ptl = (c_protocol*)p_server->get_protocol();
	assert(NULL != p_ptl);
	unsigned ui_threadid = GetCurrentThreadId();
	unsigned ui_sendbufsize = p_server->get_sendbufsize();
	unsigned ui_rcvbufsize = p_server->get_rcvbufsize();
	unsigned ui_sendbufidxlimit = ui_sendbufsize / 2;
	unsigned ui_rcvbufidxlimit = ui_sendbufsize / 4 * 3;

	p_server->inc_acctivethreadcnt();
	
	unsigned         ui_interval = p_server->get_interval();
	OVERLAPPED       *p_ol = NULL;
	c_clientcontext  *p_clientctx = NULL;
	DWORD            dw_transferbytes = 0;
	unsigned         ui_now;
	DWORD             dwBytes = 0, dwFlags = 0;
	while (p_server->b_running)
	{
		BOOL b_ret = GetQueuedCompletionStatus(
			hdl_iocp,
			&dw_transferbytes,
			(PULONG_PTR)&p_clientctx,
			&p_ol,
			(DWORD)ui_interval);

		ui_now = get_curr_usec();
		//Get the client context
		if (TRUE == b_ret)
		{
			assert(NULL != p_clientctx);
			//deal set/conditoin list
			run_clientcontext_pcdlistset(p_clientctx, ui_now);
			run_clientcontext_pcdlistcondition(p_clientctx, ui_now);

			OVERLAPPED *p_olsend = (OVERLAPPED*)p_clientctx->get_polsend();
			OVERLAPPED *p_olrcv = (OVERLAPPED*)p_clientctx->get_polreceive();
			int n_rcvhead, n_rcvtail;
			int n_sendhead, n_sendtail;
			byte *p_buf = NULL;
			byte by_connstatus = CLTCTX_STATUS_IDLE;
			byte by_newconnstatus = CLTCTX_STATUS_IDLE;
			if (p_ol == p_olrcv)
			{//receive
				by_connstatus = CLTCTX_STATUS_RCV;
				p_buf = p_clientctx->get_receivebuffer();
				n_rcvhead = p_clientctx->get_rcvhead();
				n_rcvtail = p_clientctx->get_rcvtail();
				n_rcvtail += dw_transferbytes;
				p_clientctx->ui_rcvbytes += dw_transferbytes;
				assert(n_rcvtail <= ui_rcvbufsize);
				//match receive package 
				bool b_matched = true;
				while (n_rcvhead < n_rcvtail && b_matched)
				{
					b_matched = false;
					POS pos = p_clientctx->pcdlistreceive.GetHeadPosition();
					while (NULL != pos)
					{
						POS pos_curr = pos;
						c_procedure* p_pcd = p_clientctx->pcdlistreceive.GetN
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值