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;
}