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