IOCP之WSASend,0字节探测发送。工作线程真正发送。

IOCP_WSASend函数是多线程消息包发送函数,这里会进行加锁拷贝数据到缓冲区,然后检测当前是否正在发送过程中。如果没有正在异步发送,那么投递0字节发送。

#define OVL_RECEIVE				0X01
#define OVL_SEND0				0X02
#define OVL_CLOSE				0X03
#define OVL_SENDE				0X04


// 缓冲区安全锁
	CRITICAL_SECTION m_csCache;
	// 发送缓冲区
	char *m_pCacheBuf;
	int m_nCacheLength;
	// WSASend异步投递标识,当没有投递时,先投递一个0字节的空发送
	BOOL m_bIoSending;
	// WSASend WSABuf数据和长度
	char m_bySendBuf[MAX_WSASEND_BUFF_SIZE];
	int m_nSendLength;

// debug统计
	unsigned int m_nWillSend;
	unsigned int m_nHadSend;
	// 重用次数
	int m_nInitCount;
	// 丢弃消息包数量
	int m_nDropSendCount;
case	OVL_SEND0:
			case	OVL_SENDE:
				{
					long errCode = pBSocket->IOCP_OnWSASend(nbytes, pOvl->Offset);
					if (0L != errCode)
					{
						if (WSAENOBUFS != errCode)
						{
							pBSocket->B_OnClose(errCode);
							break;
						}
					}

					// 旧代码
					pBSocket->m_ActivatedFlag = 1;
					pBSocket->B_OnSend(0);
					break;
				}
long CIOCPSocket::IOCP_WSASend( char* pBuf, long length)
{
	EnterCriticalSection(&m_csCache);
	int errCode = 0L;

	if (m_nCacheLength + length > INIT_CACHE_BUFF_SIZE)
	{
		LeaveCriticalSection(&m_csCache);
		++m_nDropSendCount;
		return errCode;
	}

	// 缓存数据
	memcpy(m_pCacheBuf + m_nCacheLength, pBuf, length);
	m_nCacheLength += length;
	
	m_nWillSend += length;

	if (!m_bIoSending) {
		//IOCP_OnWSASend();
		// 发送0字节数据包,触发真正的数据发送
		DWORD dwIoSize;
		DWORD dwFlags = 0;

		memset(&m_SendOverlap, 0, sizeof(m_SendOverlap));
		m_SendOverlap.Offset = OVL_SEND0;
		m_out.buf = m_bySendBuf;
		m_out.len = 0;
		
		// 发送数据
		m_bIoSending = TRUE;

		if (SOCKET_ERROR == WSASend(m_Socket, &m_out, 1, &dwIoSize, dwFlags, &m_SendOverlap, NULL)) 
		{
			//发送数据
			int nLastErr = WSAGetLastError();
			if (WSA_IO_PENDING != nLastErr) 
			{
				if (WSAENOBUFS == nLastErr)
				{
					// 内存分页死锁
					CMyLog::m_pLog->_XGSysLog("[WARN]IOCP_WSASend[s:%d]WSAENOBUFS.m_nCacheLength:%d,socket errCode:%d.\n", 
						m_Socket, m_nCacheLength, nLastErr);
					errCode = 0L;
				}
				else
				{
					// 断开连接时返回-1
					CMyLog::m_pLog->_XGSysLog("[ERROR]IOCP_WSASend[s:%d]m_nCacheLength:%d, m_nSendLength:%d, socket errCode:%d.\n", 
						m_Socket, m_nCacheLength, m_nSendLength, nLastErr);
					errCode = -1;
				}
			}
		}
	}

	LeaveCriticalSection(&m_csCache);

	return errCode;
}

IOCP_OnWSASend是iocp的工作线程异步WSASend的结果调用函数。这里返回发送的字节数。当投递0自己发送时,这里会加锁从缓冲区拷贝数据,真正的WSASend发送数据。WSASend的发送只要投递成功,投递的所有数据都会发送成功,不会出现只发送一部分的情况。所以m_nSendLenght在投递发送之后必定为0.也就是m_nSendLenght==nBytes。也就是(m_nSendLength -= nBytes;当nByte补位0时,m_nSendLenght==nBytes必定相等。)

long CIOCPSocket::IOCP_OnWSASend(int nBytes, int n)
{
	EnterCriticalSection(&m_csCache);
	long errCode = 0L;
	m_nSendLength -= nBytes;

	m_nHadSend += nBytes;

	if (m_nSendLength > 0)
	{
		// 这里不应该进来,进来就有问题
		if (nBytes > 0) 
		{
			// 数据没有发送完,数据前移
			memcpy(m_bySendBuf, m_bySendBuf + nBytes, m_nSendLength);
		}

		CMyLog::m_pLog->_XGSysLog("[ERROR]IOCP_OnWSASend[s:%d]n:%d.m_nCacheLength:%d, m_nSendLength:%d, nBytes:%d.m_nRecyleCount:%d.\n", 
			m_Socket, n, m_nCacheLength, m_nSendLength, nBytes, m_nInitCount);
	}
	else if (m_nSendLength < 0)
	{
		LeaveCriticalSection(&m_csCache);
		// 出现了错误!
		CMyLog::m_pLog->_XGSysLog("[ERROR]IOCP_OnWSASend[s:%d]m_nSendLength:%d.\n", m_nSendLength);
		return errCode;
	}
	else
	{
		// m_nSendLength == 0
	}

	if (m_nCacheLength > 0) 
	{
		int nCanCopyLength = MAX_WSASEND_BUFF_SIZE - m_nSendLength;
		if (m_nCacheLength > nCanCopyLength) 
		{
			// copy a part bytes from cache
			memcpy(m_bySendBuf + m_nSendLength, m_pCacheBuf, nCanCopyLength);
			m_nSendLength += nCanCopyLength;
			m_nCacheLength -= nCanCopyLength;

			CMyLog::m_pLog->_XGSysLog("[WARN]IOCP_OnWSASend[s:%d]m_nCacheLength > nCanCopyLength:%d.m_nCacheLength:%d, m_nSendLength:%d.\n", 
				m_Socket, nCanCopyLength, m_nCacheLength, m_nSendLength);
		}
		else
		{
			// copy all data from cache.
			memcpy(m_bySendBuf + m_nSendLength, m_pCacheBuf, m_nCacheLength);
			m_nSendLength += m_nCacheLength;
			m_nCacheLength = 0;
		}
	}
	
	// 异步发送数据
	if (m_nSendLength > 0) 
	{
		DWORD dwIoSize = 0;
		DWORD dwFlags = 0;

		memset(&m_SendOverlap, 0, sizeof(m_SendOverlap));
		m_SendOverlap.Offset = OVL_SENDE;
		m_out.buf = m_bySendBuf;
		m_out.len = m_nSendLength;

		//int nMiniSendLen = 9;
		//if (m_nSendLenght < nMiniSendLen) 
		//{
		//	nMiniSendLen = m_nSendLenght;
		//}
		//m_out.len = nMiniSendLen;

		m_bIoSending = TRUE;

		if (SOCKET_ERROR == WSASend(m_Socket, &m_out, 1, &dwIoSize, dwFlags, &m_SendOverlap, NULL)) 
		{
			//发送数据
			int nLastErr = WSAGetLastError();
			if (WSA_IO_PENDING != nLastErr) 
			{
				if (WSAENOBUFS == nLastErr)
				{
					// 内存分页死锁。
					m_bIoSending = FALSE;
					CMyLog::m_pLog->_XGSysLog("[WARN]IOCP_OnWSASend[s:%d]WSAENOBUFS.m_nCacheLength:%d, m_nSendLength:%d.\n", 
						m_Socket, m_nCacheLength, m_nSendLength);
					errCode = 0L;
				}
				else
				{
					// socket 错误断开
					CMyLog::m_pLog->_XGSysLog("[ERROR]IOCP_OnWSASend[s:%d]socket will close errCode:%d.m_nCacheLength:%d, m_nSendLength:%d.\n", 
						m_Socket, nLastErr, m_nCacheLength, m_nSendLength);
					errCode = nLastErr;
				}
			}
			else
			{
				CMyLog::m_pLog->_XGSysLog("[WARN]IOCP_OnWSASend[s:%d]WSA_IO_PENDING.m_nCacheLength:%d,m_nSendLength:%d.\n", 
					m_Socket, m_nCacheLength, m_nSendLength);
			}
		}
	} 
	else 
	{
		m_bIoSending = FALSE;
	}

	LeaveCriticalSection(&m_csCache);

	return 0L;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值