1681 lines
38 KiB
C++
1681 lines
38 KiB
C++
#include "stdafx.h"
|
||
#include "IOCP.h"
|
||
|
||
#pragma comment(lib, "ws2_32.lib")
|
||
|
||
#include "..\SmsCenterDlg.h"
|
||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
CIOCP::CIOCP()
|
||
{
|
||
m_pDlg = NULL;
|
||
m_listen_socket = INVALID_SOCKET;
|
||
m_listen_socket2 = INVALID_SOCKET;
|
||
m_bInitSocket = false;
|
||
m_bInitSocket2 = false;
|
||
m_bInit = false;
|
||
|
||
m_h_MainLoop = INVALID_HANDLE_VALUE;
|
||
m_h_MainLoop2 = INVALID_HANDLE_VALUE;
|
||
m_bQuit = false;
|
||
}
|
||
|
||
|
||
CIOCP::~CIOCP()
|
||
{
|
||
Close();
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:关闭并清除资源
|
||
函数说明:
|
||
函数返回:
|
||
-------------------------------------------------------------------------------------------*/
|
||
void CIOCP::Close()
|
||
{
|
||
try
|
||
{
|
||
int i;
|
||
|
||
if ( !m_bInit )
|
||
return ;
|
||
|
||
m_bQuit = true;
|
||
|
||
if (m_h_MainLoop!=INVALID_HANDLE_VALUE )
|
||
{
|
||
if (WaitForSingleObject(m_h_MainLoop,3000)== WAIT_TIMEOUT )
|
||
TerminateThread(m_h_MainLoop,0); //如果退出超时,强制结束线程
|
||
CloseHandle(m_h_MainLoop);
|
||
m_h_MainLoop = INVALID_HANDLE_VALUE;
|
||
}
|
||
|
||
if (m_h_MainLoop2!=INVALID_HANDLE_VALUE )
|
||
{
|
||
if ( WaitForSingleObject(m_h_MainLoop2,3000)== WAIT_TIMEOUT )
|
||
TerminateThread(m_h_MainLoop2,0); //如果退出超时,强制结束线程
|
||
CloseHandle(m_h_MainLoop2);
|
||
m_h_MainLoop2 = INVALID_HANDLE_VALUE;
|
||
}
|
||
|
||
PostQueuedCompletionStatus( m_h_iocp, 0, 0, NULL );
|
||
CloseHandle( m_h_iocp );
|
||
|
||
for( i = 0; i < m_n_thread_count; i++ )
|
||
{
|
||
if (m_h_thread[i]!=INVALID_HANDLE_VALUE )
|
||
{
|
||
if ( WaitForSingleObject(m_h_thread[i],1000)== WAIT_TIMEOUT )
|
||
TerminateThread(m_h_thread[i],0); //如果退出超时,强制结束线程
|
||
CloseHandle( m_h_thread[i] );
|
||
m_h_thread[i] = INVALID_HANDLE_VALUE;
|
||
}
|
||
}
|
||
Sleep(200); //等待其它的退出
|
||
m_KeyList.Close();
|
||
CloseMainSocket();
|
||
m_bInit = false;
|
||
}
|
||
catch (...)
|
||
{
|
||
LOG_APPERROR(_T("T"));
|
||
}
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:初始化IO结点
|
||
函数说明:
|
||
函数返回:
|
||
-------------------------------------------------------------------------------------------*/
|
||
void CIOCP::InitIoContext(IOCP_IO_PTR lp_io)
|
||
{
|
||
if ( !lp_io )
|
||
return ;
|
||
try
|
||
{
|
||
if ( lp_io< &m_KeyList.m_IO[0] || lp_io>&m_KeyList.m_IO[MAX_LOGINUSER] )
|
||
return ;
|
||
|
||
memset( &lp_io->ol, 0, sizeof( WSAOVERLAPPED ) );
|
||
//memset( &lp_io->buf, 0, BUFFER_SIZE );
|
||
lp_io->wsaBuf.buf = lp_io->buf;
|
||
lp_io->wsaBuf.len = BUFFER_SIZE;
|
||
lp_io->lRecvLen = 0;
|
||
}
|
||
catch (...)
|
||
{
|
||
LOG_APPERROR(_T("T"));
|
||
}
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:初始化侦听SOCKET端口,并和完成端口连接起来。
|
||
函数说明:
|
||
函数返回:成功,TRUE;失败,FALSE
|
||
-------------------------------------------------------------------------------------------*/
|
||
BOOL CIOCP::InitSocket()
|
||
{
|
||
//端口1初始化
|
||
m_listen_socket = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED );
|
||
if( INVALID_SOCKET == m_listen_socket )
|
||
{
|
||
return FALSE;
|
||
}
|
||
//IOCP_KEY_PTR lp_key = m_key_group.GetBlank();
|
||
IOCP_KEY_PTR lp_key = m_KeyList.GetBlank_Key();
|
||
if ( !lp_key )
|
||
return FALSE;
|
||
|
||
lp_key->socket = m_listen_socket;
|
||
|
||
HANDLE hRet = CreateIoCompletionPort( (HANDLE)m_listen_socket, m_h_iocp, (ULONG_PTR)lp_key, 0 );
|
||
if( hRet == NULL )
|
||
{
|
||
CloseOneSocket( m_listen_socket );
|
||
//m_key_group.RemoveAt( lp_key );
|
||
m_KeyList.RemoveAt_Key( lp_key );
|
||
return FALSE;
|
||
}
|
||
|
||
//端口2初始化
|
||
m_listen_socket2 = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED );
|
||
if( INVALID_SOCKET == m_listen_socket2 )
|
||
{
|
||
return FALSE;
|
||
}
|
||
//IOCP_KEY_PTR lp_key2 = m_key_group.GetBlank();
|
||
IOCP_KEY_PTR lp_key2 = m_KeyList.GetBlank_Key();
|
||
lp_key2->socket = m_listen_socket2;
|
||
|
||
hRet = CreateIoCompletionPort( (HANDLE)m_listen_socket2, m_h_iocp, (ULONG_PTR)lp_key2, 0 );
|
||
if( hRet == NULL )
|
||
{
|
||
CloseOneSocket( m_listen_socket );
|
||
//m_key_group.RemoveAt( lp_key );
|
||
m_KeyList.RemoveAt_Key( lp_key );
|
||
CloseOneSocket( m_listen_socket2 );
|
||
//m_key_group.RemoveAt( lp_key2 );
|
||
m_KeyList.RemoveAt_Key( lp_key2 );
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:关闭所有线程
|
||
函数说明:
|
||
函数返回:
|
||
-------------------------------------------------------------------------------------------*/
|
||
void CIOCP::CloseThreadHandle(int count )
|
||
{
|
||
if( count <= 0 )
|
||
{
|
||
return;
|
||
}
|
||
|
||
for( int i= 0; i < count; i++ )
|
||
{
|
||
if (m_h_thread[i]!=INVALID_HANDLE_VALUE )
|
||
{
|
||
if ( WaitForSingleObject(m_h_thread[i],1000)== WAIT_TIMEOUT )
|
||
TerminateThread(m_h_thread[i],0); //如果退出超时,强制结束线程
|
||
CloseHandle( m_h_thread[i] );
|
||
m_h_thread[i] = INVALID_HANDLE_VALUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:将侦听端口和自己的IP,PORT绑定,并开始侦听
|
||
函数说明:
|
||
函数返回:成功,TRUE;失败,FALSE
|
||
-------------------------------------------------------------------------------------------*/
|
||
BOOL CIOCP::BindAndListenSocket()
|
||
{
|
||
SOCKADDR_IN addr;
|
||
|
||
memset( &addr, 0, sizeof(SOCKADDR_IN) );
|
||
|
||
addr.sin_family = AF_INET;
|
||
//addr.sin_addr.s_addr = inet_addr( ADDR );
|
||
//addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||
addr.sin_addr.s_addr = m_pDlg->m_Setup.addr;
|
||
#ifdef UNICODE
|
||
addr.sin_port = htons( DEFAULT_SERVERPORT_UNI );
|
||
#else
|
||
addr.sin_port = htons( DEFAULT_LISTENPORT );
|
||
#endif
|
||
|
||
|
||
int nRet;
|
||
|
||
nRet = bind( m_listen_socket, (SOCKADDR*)&addr, sizeof( SOCKADDR ) );
|
||
|
||
if( SOCKET_ERROR == nRet)
|
||
{
|
||
//cout<<"bind fail!"<<endl;
|
||
int er = WSAGetLastError();
|
||
return FALSE;
|
||
}
|
||
|
||
nRet = listen( m_listen_socket, 50 );
|
||
|
||
if( SOCKET_ERROR == nRet )
|
||
{
|
||
//cout<<"listen fail!"<<endl;
|
||
return FALSE;
|
||
}
|
||
m_bInitSocket = true;
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:根据CPU的数目,启动相应数量的数据处理线程
|
||
函数说明:
|
||
函数返回:成功,TRUE;失败,FALSE
|
||
-------------------------------------------------------------------------------------------*/
|
||
BOOL CIOCP::StartThread()
|
||
{
|
||
int i;
|
||
|
||
SYSTEM_INFO sys_info;
|
||
|
||
GetSystemInfo( &sys_info );
|
||
|
||
m_n_thread_count = sys_info.dwNumberOfProcessors*2;
|
||
if (m_n_thread_count<2 || m_n_thread_count>MAXTHREAD_COUNT )
|
||
m_n_thread_count = MAXTHREAD_COUNT;
|
||
|
||
//m_n_thread_count = 4;
|
||
for( i = 0; i < m_n_thread_count; i++ )
|
||
{
|
||
m_h_thread[i] = CreateThread( NULL, 0, CompletionRoutine, (LPVOID)this, 0, NULL );
|
||
|
||
if( INVALID_HANDLE_VALUE == m_h_thread[i] )
|
||
{
|
||
CloseThreadHandle( i );
|
||
CloseHandle( m_h_iocp );
|
||
return FALSE;
|
||
}
|
||
}
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:发出一定数量的连接
|
||
函数说明:
|
||
函数返回:成功,TRUE;失败,FALSE
|
||
-------------------------------------------------------------------------------------------*/
|
||
BOOL CIOCP::PostAcceptEx()
|
||
{
|
||
#ifdef _DEBUG
|
||
int count = 10;
|
||
#else
|
||
int count = 30;
|
||
#endif
|
||
|
||
DWORD dwBytes;
|
||
BOOL bRet;
|
||
|
||
for( int i = 0; i < count; i++ )
|
||
{
|
||
SOCKET socket = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED );
|
||
|
||
if( INVALID_SOCKET == socket )
|
||
{
|
||
//cout<<"post accept ex fail!"<<WSAGetLastError()<<endl;
|
||
continue;
|
||
}
|
||
|
||
//设置Socket
|
||
int ulTemp=1; //将SOCKET设成非阻塞式的SOCKET
|
||
//u_long ulTemp=0; //将SOCKET设成阻塞式的SOCKET
|
||
//ioctlsocket( socket,FIONBIO,&ulTemp );
|
||
|
||
ulTemp=128*1024;
|
||
setsockopt( socket , SOL_SOCKET, SO_SNDBUF ,(const char *)&ulTemp ,sizeof(ulTemp)); //设绶冲
|
||
ulTemp=64*1024;
|
||
setsockopt( socket , SOL_SOCKET, SO_RCVBUF ,(const char *)&ulTemp ,sizeof(ulTemp)); //设绶冲
|
||
/*
|
||
setsockopt( socket, SOL_SOCKET, SO_DONTLINGER,(const char *)&ulTemp,sizeof(BOOL));
|
||
struct linger {
|
||
u_short l_onoff;
|
||
u_short l_linger;
|
||
};
|
||
linger m_sLinger;
|
||
m_sLinger.l_onoff=0;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留)
|
||
// 如果m_sLinger.l_onoff=0;则功能和2.)作用相同;
|
||
m_sLinger.l_linger=0;//(容许逗留的时间为5秒)
|
||
int iLen=sizeof(m_sLinger);
|
||
int i = setsockopt(socket,SOL_SOCKET,SO_LINGER,(const char*)&m_sLinger,sizeof(linger));
|
||
*/
|
||
// int lLen=sizeof(ulTemp);
|
||
// getsockopt( socket , SOL_SOCKET, SO_SNDBUF ,(char *)&ulTemp ,&lLen); //设绶冲
|
||
|
||
IOCP_IO_PTR lp_io = m_KeyList.GetBlank_IO();
|
||
if ( lp_io != NULL )
|
||
{
|
||
InitIoContext( lp_io );
|
||
lp_io->socket = socket;
|
||
lp_io->operation = IOCP_ACCEPT;
|
||
lp_io->state = SOCKET_STATE_NOT_CONNECT;
|
||
/////////////////////////////////////////////////
|
||
bRet = lpAcceptEx(
|
||
m_listen_socket,
|
||
lp_io->socket,
|
||
lp_io->buf,
|
||
// lp_io->wsaBuf.len - 2 * ( sizeof(SOCKADDR_IN) + 16 ),
|
||
0,
|
||
sizeof(SOCKADDR_IN) + 16,
|
||
sizeof(SOCKADDR_IN) + 16,
|
||
&dwBytes,&lp_io->ol);
|
||
if( ( bRet == FALSE ) && ( WSA_IO_PENDING != WSAGetLastError() ) )
|
||
{
|
||
closesocket( socket );
|
||
//m_io_group.RemoveAt( lp_io );
|
||
m_KeyList.RemoveAt_IO( lp_io );
|
||
//cout<<"post acceptex fail:"<<WSAGetLastError()<<endl;
|
||
continue;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
int i=10;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:处理数据函数
|
||
函数说明:
|
||
函数返回:成功,TRUE;失败,FALSE
|
||
-------------------------------------------------------------------------------------------*/
|
||
BOOL CIOCP::HandleData(IOCP_IO_PTR lp_io,IOCP_KEY_PTR lp_key, int nFlags)
|
||
{
|
||
switch( nFlags )
|
||
{
|
||
case IOCP_COMPLETE_ACCEPT:
|
||
{
|
||
InitIoContext( lp_io );
|
||
lp_io->operation = IOCP_READ;
|
||
}
|
||
break;
|
||
case IOCP_COMPLETE_ACCEPT_READ:
|
||
{
|
||
/*
|
||
lp_io->operation = IOCP_WRITE;
|
||
|
||
GetAddrAndPort( lp_io->wsaBuf.buf, szAddress, uPort );
|
||
|
||
//MSG(lp_io->wsaBuf.len);
|
||
memset( &lp_io->ol, 0, sizeof(lp_io->ol) );
|
||
*/
|
||
}
|
||
break;
|
||
case IOCP_COMPLETE_READ:
|
||
{
|
||
//cout<<"read a data!*******************************"<<endl;
|
||
|
||
lp_io->lRecvLen += lp_io->wsaBuf.len;
|
||
|
||
long lRet=0;
|
||
if ( lp_io->m_lLocalPort == DEFAULT_LISTENPORT2 )
|
||
lRet = GetFrame_Cmpp(lp_io);
|
||
else
|
||
lRet = GetFrame(lp_io);
|
||
if ( lRet < 0 )
|
||
{
|
||
//处理帧失败
|
||
m_KeyList.RemoveAt_IO( lp_io );
|
||
m_KeyList.RemoveAt_Key( lp_key );
|
||
closesocket( lp_io->socket );
|
||
lp_io->operation = IOCP_END; //关闭后不用处理了
|
||
}
|
||
else
|
||
{
|
||
//接收到的数据过大,并且没有合适的包。
|
||
if ( lp_io->lRecvLen>=BUFFER_SIZE )
|
||
{
|
||
m_KeyList.RemoveAt_IO( lp_io );
|
||
m_KeyList.RemoveAt_Key( lp_key );
|
||
closesocket( lp_io->socket );
|
||
lp_io->operation = IOCP_END; //关闭后不用处理了
|
||
}
|
||
else
|
||
{
|
||
//重新开始投射io
|
||
lp_io->operation = IOCP_READ;
|
||
memset( &lp_io->ol, 0, sizeof(lp_io->ol) );
|
||
|
||
lp_io->wsaBuf.buf = lp_io->buf + lp_io->lRecvLen;
|
||
lp_io->wsaBuf.len = BUFFER_SIZE-lp_io->lRecvLen;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
case IOCP_COMPLETE_WRITE:
|
||
{
|
||
try
|
||
{
|
||
IOCP_IO_SEND_PTR ioS = (IOCP_IO_SEND_PTR)lp_io;
|
||
|
||
if ( ioS->wsaBuf.len >0 )
|
||
{
|
||
if ( ioS->wsaBuf.buf )
|
||
delete ioS->wsaBuf.buf;
|
||
ioS->wsaBuf.buf = NULL;
|
||
}
|
||
delete ioS;
|
||
}
|
||
catch (...)
|
||
{
|
||
LOG_APPERROR(_T("T"));
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
{
|
||
//cout<<"handleData do nothing!*********************"<<endl;
|
||
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:发出一些重叠动作
|
||
函数说明:
|
||
函数返回:成功,TRUE;失败,FALSE
|
||
-------------------------------------------------------------------------------------------*/
|
||
BOOL CIOCP::DataAction(IOCP_IO_PTR lp_io, IOCP_KEY_PTR lp_key )
|
||
{
|
||
DWORD dwBytes;
|
||
int nRet;
|
||
DWORD dwFlags;
|
||
|
||
switch( lp_io->operation )
|
||
{
|
||
case IOCP_WRITE:
|
||
{
|
||
nRet = WSASend(
|
||
lp_io->socket,
|
||
&lp_io->wsaBuf,
|
||
1,
|
||
&dwBytes,
|
||
0,
|
||
&lp_io->ol,NULL);
|
||
|
||
if( ( nRet == SOCKET_ERROR ) && ( WSAGetLastError() != WSA_IO_PENDING ) )
|
||
{
|
||
m_KeyList.RemoveAt_IO( lp_io );
|
||
m_KeyList.RemoveAt_Key( lp_key );
|
||
closesocket( lp_io->socket );
|
||
return FALSE;
|
||
}
|
||
}
|
||
break;
|
||
case IOCP_WRITE2:
|
||
{
|
||
/*
|
||
IOCP_IO_SEND_PTR ioS = (IOCP_IO_SEND_PTR)lp_io;
|
||
|
||
ioS->operation = IOCP_WRITE;
|
||
nRet = WSASend(
|
||
lp_key->socket,
|
||
&ioS->wsaBuf[ioS->lSendNowIndex-1],
|
||
1,
|
||
&dwBytes,
|
||
0,
|
||
&ioS->ol,NULL);
|
||
/*
|
||
if( ( nRet == SOCKET_ERROR ) && ( WSAGetLastError() != WSA_IO_PENDING ) )
|
||
{
|
||
//cout<<"WSASend fail!----------------------------------------"<<WSAGetLastError()<<endl;
|
||
|
||
closesocket( lp_io->socket );
|
||
|
||
//m_io_group.RemoveAt( lp_io );
|
||
m_KeyList.RemoveAt_IO( lp_io );
|
||
//m_key_group.RemoveAt( lp_key );
|
||
m_KeyList.RemoveAt_Key( lp_key );
|
||
|
||
return FALSE;
|
||
}
|
||
*/
|
||
}
|
||
break;
|
||
case IOCP_READ:
|
||
{
|
||
//cout<<"post a read data!-----------------------------------------"<<endl;
|
||
|
||
dwFlags = 0;
|
||
|
||
nRet = WSARecv(
|
||
lp_io->socket,
|
||
&lp_io->wsaBuf,
|
||
1,
|
||
&dwBytes,
|
||
&dwFlags,
|
||
&lp_io->ol,NULL);
|
||
|
||
if( ( nRet == SOCKET_ERROR ) && ( WSAGetLastError() != WSA_IO_PENDING ) )
|
||
{
|
||
m_KeyList.RemoveAt_IO( lp_io );
|
||
m_KeyList.RemoveAt_Key( lp_key );
|
||
closesocket( lp_io->socket );
|
||
|
||
return FALSE;
|
||
}
|
||
}
|
||
break;
|
||
case IOCP_END:
|
||
break;
|
||
default:
|
||
{
|
||
//cout<<"DataAction do nothing!------------------------------------------"<<endl;
|
||
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:得到MS封装的SOCKET函数指针,这样可以提高速度
|
||
函数说明:
|
||
函数返回:成功,TRUE;失败,FALSE
|
||
-------------------------------------------------------------------------------------------*/
|
||
BOOL CIOCP::GetFunPointer()
|
||
{
|
||
DWORD dwRet,nRet;
|
||
|
||
nRet = WSAIoctl(
|
||
m_listen_socket,
|
||
SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||
&g_GUIDAcceptEx,
|
||
sizeof(g_GUIDAcceptEx),
|
||
&lpAcceptEx,
|
||
sizeof(lpAcceptEx),
|
||
&dwRet,NULL,NULL);
|
||
|
||
if( SOCKET_ERROR == nRet )
|
||
{
|
||
CloseOneSocket(m_listen_socket);
|
||
//cout<<"get acceptex fail!"<<WSAGetLastError()<<endl;
|
||
return FALSE;
|
||
}
|
||
|
||
nRet = WSAIoctl(
|
||
m_listen_socket,
|
||
SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||
&g_GUIDTransmitFile,
|
||
sizeof(g_GUIDTransmitFile),
|
||
&lpTransmitFile,
|
||
sizeof(lpTransmitFile),
|
||
&dwRet,NULL,NULL);
|
||
|
||
if(nRet == SOCKET_ERROR )
|
||
{
|
||
CloseOneSocket(m_listen_socket);
|
||
//cout<<"get transmitfile fail!"<<WSAGetLastError()<<endl;
|
||
return FALSE;
|
||
}
|
||
|
||
nRet = WSAIoctl(
|
||
m_listen_socket,
|
||
SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||
&g_GUIDAcceptExaddrs,
|
||
sizeof(g_GUIDAcceptExaddrs),
|
||
&lpGetAcceptExSockAddrs,
|
||
sizeof(lpGetAcceptExSockAddrs),
|
||
&dwRet,NULL,NULL);
|
||
|
||
if(nRet == SOCKET_ERROR )
|
||
{
|
||
CloseOneSocket(m_listen_socket);
|
||
//cout<<"get transmitfile fail!"<<WSAGetLastError()<<endl;
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:看看是否有连接了,但很长时间没有数据的“无效连接”,有的话,就踢掉
|
||
函数说明:
|
||
函数返回:成功,TRUE;失败,FALSE
|
||
-------------------------------------------------------------------------------------------*/
|
||
void CIOCP::CheckForInvalidConnection()
|
||
{
|
||
try
|
||
{
|
||
TCHAR szMsg[256]={0};
|
||
DWORD dwNow = ::GetTickCount();
|
||
|
||
IOCP_IO_PTR lp_io = m_KeyList.m_IO;
|
||
if ( !lp_io )
|
||
return ;
|
||
for ( int i=0 ; i< MAX_LOGINUSER ; i++ )
|
||
{
|
||
if ( lp_io[i].socket != NULL && lp_io[i].socket!=INVALID_SOCKET && lp_io[i].lRandID>0 )
|
||
{
|
||
if (lp_io[i].dwAcceptTime>0 && lp_io[i].state != SOCKET_STATE_CONNECT_AND_READ )
|
||
{
|
||
/*
|
||
op_len = sizeof(op);
|
||
nRet = getsockopt( lp_io[i].socket, SOL_SOCKET, SO_CONNECT_TIME, (char*)&op, &op_len );
|
||
if( SOCKET_ERROR == nRet )
|
||
{
|
||
continue;
|
||
}
|
||
if( op != 0xffffffff && op > 3 ) //3秒连接超时
|
||
{
|
||
sprintf(szMsg , "[%d]%s:%d 连接超时!" , lp_io[i].m_lLocalPort,lp_io[i].m_szIP,lp_io[i].m_lPort);
|
||
m_pDlg->AddLog(szMsg);
|
||
closesocket( lp_io[i].socket );
|
||
}
|
||
*/
|
||
if ( dwNow - lp_io[i].dwAcceptTime >5000 ) //10秒连接超时
|
||
{
|
||
_stprintf(szMsg , _T("[%d]%s:%d 连接超时!") , lp_io[i].m_lLocalPort,lp_io[i].m_szIP,lp_io[i].m_lPort);
|
||
m_pDlg->AddLog(szMsg);
|
||
closesocket( lp_io[i].socket );
|
||
}
|
||
}
|
||
if ( lp_io[i].state == SOCKET_STATE_CONNECT_AND_READ )
|
||
{
|
||
if ( lp_io[i].dwEndRecvFrame>0 )
|
||
{
|
||
if ( dwNow - lp_io[i].dwEndRecvFrame > RECVREFRESH_TIMEOUT )
|
||
{
|
||
lp_io[i].m_lID = 199992; //断线退出的标志
|
||
closesocket( lp_io[i].socket );
|
||
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ( dwNow - lp_io[i].dwAcceptTime > 40000 ) //30秒没收到正确的包就超时
|
||
{
|
||
_stprintf(szMsg , _T("[%d]%s:%d 接收数据超时!") , lp_io[i].m_lLocalPort,lp_io[i].m_szIP,lp_io[i].m_lPort);
|
||
m_pDlg->AddLog(szMsg);
|
||
closesocket( lp_io[i].socket );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (...)
|
||
{
|
||
LOG_APPERROR(_T("T"));
|
||
}
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:注册FD_ACCEPTG事件到m_h_accept_event事件,以便所有发出去的连接耗耗尽时,得到通知。
|
||
函数说明:
|
||
函数返回:成功,TRUE;失败,FALSE
|
||
-------------------------------------------------------------------------------------------*/
|
||
BOOL CIOCP::RegAcceptEvent()
|
||
{
|
||
int nRet;
|
||
|
||
m_h_accept_event = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||
|
||
if( NULL == m_h_accept_event )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
nRet = WSAEventSelect( m_listen_socket, m_h_accept_event, FD_ACCEPT );
|
||
|
||
if( nRet != 0 )
|
||
{
|
||
CloseHandle( m_h_accept_event );
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:得到连接上来的客户端IP和PORT
|
||
函数说明:
|
||
函数返回:成功,TRUE;失败,FALSE
|
||
-------------------------------------------------------------------------------------------*/
|
||
BOOL CIOCP::GetAddrAndPort(char*buf,char ip[],UINT &port)
|
||
{
|
||
int len = BUFFER_SIZE - sizeof( SOCKADDR_IN ) - 16;
|
||
char *lp_buf = buf + len; //直接读取远端地址
|
||
|
||
SOCKADDR_IN addr;
|
||
|
||
memcpy( &addr, lp_buf, sizeof( SOCKADDR_IN ) );
|
||
|
||
port = ntohl( addr.sin_port );
|
||
strcpy( ip, inet_ntoa( addr.sin_addr ) );
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
///////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:初始化完成端口及相关的所有东西,并发出每一个10个连接.
|
||
函数说明:
|
||
函数返回:成功,TRUE;失败,FALSE
|
||
-------------------------------------------------------------------------------------------*/
|
||
BOOL CIOCP::Init()
|
||
{
|
||
BOOL b1;
|
||
BOOL b2;
|
||
WSAData data;
|
||
if( WSAStartup( MAKEWORD(2,2),&data) != 0 )
|
||
{
|
||
//cout<<"WSAStartup fail!"<<WSAGetLastError() << endl;
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
m_KeyList.Init(m_pDlg);
|
||
m_h_iocp = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, NULL, 0 );
|
||
|
||
if( NULL == m_h_iocp )
|
||
{
|
||
//cout << "CreateIoCompletionPort() failed: " << GetLastError() << endl;
|
||
return FALSE;
|
||
}
|
||
|
||
if( !StartThread() )
|
||
{
|
||
//cout<<"start thread fail!"<<endl;
|
||
|
||
Close();
|
||
//PostQueuedCompletionStatus( m_h_iocp, 0, NULL, NULL );
|
||
//CloseHandle( m_h_iocp );
|
||
return FALSE;
|
||
}
|
||
|
||
if( !InitSocket() )
|
||
{
|
||
Close();
|
||
//PostQueuedCompletionStatus( m_h_iocp, 0, NULL, NULL );
|
||
//CloseHandle( m_h_iocp );
|
||
return FALSE;
|
||
}
|
||
|
||
if ( !BindAndListenSocket() ) //绑定端口1
|
||
{
|
||
Close();
|
||
return FALSE;
|
||
}
|
||
|
||
m_bInitSocket2=false; //不启用7890端口
|
||
/*
|
||
#ifndef UNICODE
|
||
if ( !BindAndListenSocket2()) //绑定端口2
|
||
{
|
||
Close();
|
||
return FALSE;
|
||
}
|
||
#endif
|
||
*/
|
||
if( !m_bInitSocket && !m_bInitSocket2 ) //两个端口初始化都不成功
|
||
{
|
||
Close();
|
||
//PostQueuedCompletionStatus( m_h_iocp, 0, NULL, NULL );
|
||
//CloseHandle( m_h_iocp );
|
||
//CloseMainSocket();
|
||
|
||
return FALSE;
|
||
}
|
||
if ( !GetFunPointer() )
|
||
{
|
||
Close();
|
||
//PostQueuedCompletionStatus( m_h_iocp, 0, NULL, NULL );
|
||
//CloseHandle( m_h_iocp );
|
||
//CloseMainSocket();
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
b1 = true;
|
||
if (m_bInitSocket)
|
||
b1=PostAcceptEx();
|
||
b2 = true;
|
||
if (m_bInitSocket2)
|
||
b2=PostAcceptEx2();
|
||
|
||
if ( !b1 && !b2 )
|
||
{
|
||
Close();
|
||
//PostQueuedCompletionStatus( m_h_iocp, 0, NULL, NULL );
|
||
//CloseHandle( m_h_iocp );
|
||
//CloseMainSocket();
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
b1 = true;
|
||
if (m_bInitSocket)
|
||
b1=RegAcceptEvent();
|
||
b2 = true;
|
||
if (m_bInitSocket2)
|
||
b1=RegAcceptEvent2();
|
||
if ( !b1 && !b2 )
|
||
{
|
||
Close();
|
||
//PostQueuedCompletionStatus( m_h_iocp, 0, NULL, NULL );
|
||
//CloseHandle( m_h_iocp );
|
||
//CloseMainSocket();
|
||
|
||
return FALSE;
|
||
}
|
||
m_bInit = true;
|
||
|
||
m_bQuit = false; //主线程不允许退出
|
||
m_h_MainLoop = CreateThread( NULL, 0, MainLoop, (LPVOID)this, 0, NULL );
|
||
if ( m_h_MainLoop == INVALID_HANDLE_VALUE ) //主线程创建不成功
|
||
{
|
||
this->Close();
|
||
return false;
|
||
}
|
||
|
||
//if( m_bInitSocket2 )
|
||
//{
|
||
m_h_MainLoop2 = CreateThread( NULL, 0, MainLoop2, (LPVOID)this, 0, NULL );
|
||
if ( m_h_MainLoop2 == INVALID_HANDLE_VALUE ) //主线程创建不成功
|
||
{
|
||
this->Close();
|
||
return false;
|
||
}
|
||
//}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:主循环
|
||
函数说明:
|
||
函数返回:成功,TRUE;失败,FALSE
|
||
-------------------------------------------------------------------------------------------*/
|
||
DWORD CIOCP::MainLoop(LPVOID lp_param)
|
||
{
|
||
try
|
||
{
|
||
AutoCoInitializeEx AutoCoInit; //自动初始化与结束Com环境
|
||
|
||
CIOCP * piocp = (CIOCP *)lp_param;
|
||
DWORD dwRet;
|
||
while( !piocp->m_bQuit )
|
||
{
|
||
dwRet = WaitForSingleObject( piocp->m_h_accept_event, 300 );
|
||
switch( dwRet )
|
||
{
|
||
case WAIT_FAILED:
|
||
{
|
||
|
||
CString str;
|
||
str.Format( _T("Accept_Event Error:%d") , GetLastError());
|
||
piocp->m_pDlg->AddLog(str);
|
||
piocp->m_pDlg->ON_TD_StopAll2(); //可能是资源不够造成失败,停止所有通道
|
||
|
||
piocp->PostAcceptEx();
|
||
|
||
//AfxMessageBox( _T("accept_event Error!") );
|
||
//PostQueuedCompletionStatus( m_h_iocp, 0, 0, NULL );
|
||
//return FALSE;
|
||
|
||
}
|
||
break;
|
||
case WAIT_TIMEOUT:
|
||
{
|
||
//CheckForInvalidConnection();
|
||
}
|
||
break;
|
||
case WAIT_OBJECT_0: //接收到了所有发出的连接都用光了的消息,再次发出连接
|
||
{
|
||
piocp->PostAcceptEx();
|
||
}
|
||
break;
|
||
}
|
||
/*
|
||
#ifndef UNICODE
|
||
dwRet = WaitForSingleObject( piocp->m_h_accept_event2, 300 );
|
||
switch( dwRet )
|
||
{
|
||
case WAIT_FAILED:
|
||
{
|
||
AfxMessageBox( _T("accept_event2 Error!") );
|
||
//PostQueuedCompletionStatus( m_h_iocp, 0, 0, NULL );
|
||
//return FALSE;
|
||
}
|
||
break;
|
||
case WAIT_TIMEOUT:
|
||
{
|
||
//CheckForInvalidConnection();
|
||
}
|
||
break;
|
||
case WAIT_OBJECT_0: //接收到了所有发出的连接都用光了的消息,再次发出连接
|
||
{
|
||
piocp->PostAcceptEx2();
|
||
}
|
||
break;
|
||
}
|
||
#endif
|
||
*/
|
||
/*
|
||
nCount ++;
|
||
if ( nCount>5 ) //每5秒检测一次超时
|
||
{
|
||
nCount=0;
|
||
//每个event等待1秒,加起来就是2秒,可以检测连接没有数据的socket
|
||
piocp->CheckForInvalidConnection();
|
||
}
|
||
*/
|
||
}
|
||
return TRUE;
|
||
}
|
||
catch(...)
|
||
{
|
||
LOG_APPERROR(_T("T"));
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/*-------------------------------------------------------------------------------------------
|
||
函数功能:数据处理线程函数
|
||
函数说明:
|
||
函数返回:
|
||
-------------------------------------------------------------------------------------------*/
|
||
DWORD CIOCP::CompletionRoutine(LPVOID lp_param)
|
||
{
|
||
USES_CONVERSION;
|
||
try
|
||
{
|
||
AutoCoInitializeEx AutoCoInit; //自动初始化与结束Com环境
|
||
|
||
CIOCP* lp_this = (CIOCP*)lp_param;
|
||
|
||
int nRet;
|
||
BOOL bRet;
|
||
DWORD dwBytes = 0;
|
||
HANDLE hRet;
|
||
|
||
IOCP_KEY_PTR lp_key = NULL;
|
||
IOCP_IO_PTR lp_io = NULL;
|
||
LPWSAOVERLAPPED lp_ov = NULL;
|
||
IOCP_KEY_PTR lp_new_key = NULL;
|
||
|
||
while( TRUE )
|
||
{
|
||
bRet = GetQueuedCompletionStatus( lp_this->m_h_iocp, &dwBytes, (PULONG_PTR)&lp_key, &lp_ov, INFINITE );
|
||
if ( lp_this->m_bQuit ) //收到退出信号
|
||
return 0;
|
||
lp_io = (IOCP_IO_PTR)lp_ov;
|
||
if ( lp_io && !AfxIsValidAddress(&lp_io->operation,4,true) ) //收到的lp_io有问题
|
||
continue;
|
||
if ( (bRet==0 || dwBytes ==0 ) && lp_io && lp_io->operation== IOCP_WRITE ) //删除不成功的Write
|
||
{
|
||
lp_this->HandleData( lp_io, lp_key, IOCP_COMPLETE_WRITE );
|
||
continue;
|
||
}
|
||
if( bRet == 0 )
|
||
{
|
||
if ( lp_key && lp_io && lp_io->lRandID>0 )
|
||
{
|
||
lp_this->m_KeyList.RemoveAt_IO( lp_io );
|
||
lp_this->m_KeyList.RemoveAt_Key( lp_key );
|
||
continue;
|
||
}
|
||
if ( (!lp_key && !lp_io) )
|
||
{
|
||
continue;
|
||
//return 0; //已退出
|
||
}
|
||
//cout << "GetQueuedCompletionStatus() failed: " << GetLastError() << endl;
|
||
//continue;
|
||
}
|
||
if( NULL == lp_key )
|
||
{
|
||
continue;
|
||
//return 0;
|
||
}
|
||
if( lp_io == NULL )
|
||
{
|
||
//cout<<"recv a null CIoContext!"<<endl;
|
||
continue;
|
||
}
|
||
|
||
if ( lp_io&& lp_io->operation!=IOCP_WRITE && (lp_io< &lp_this->m_KeyList.m_IO[0] || lp_io>&lp_this->m_KeyList.m_IO[MAX_LOGINUSER]) )
|
||
continue;
|
||
if ( lp_key && (lp_key< &lp_this->m_KeyList.m_Key[0] || lp_key>&lp_this->m_KeyList.m_Key[MAX_LOGINUSER]) )
|
||
continue;
|
||
|
||
if( ( IOCP_ACCEPT != lp_io->operation ) && ( 0 == dwBytes ) )
|
||
{
|
||
closesocket( lp_io->socket );
|
||
//lp_this->m_io_group.RemoveAt( lp_io );
|
||
//lp_this->m_key_group.RemoveAt( lp_key );
|
||
lp_this->m_KeyList.RemoveAt_IO( lp_io );
|
||
lp_this->m_KeyList.RemoveAt_Key( lp_key );
|
||
//MSG("一个用户退出了");
|
||
continue;
|
||
}
|
||
|
||
switch( lp_io->operation )
|
||
{
|
||
case IOCP_ACCEPT:
|
||
{
|
||
//cout<<"接收到一个连接"<<endl;
|
||
lp_io->state = SOCKET_STATE_CONNECT;
|
||
if( dwBytes > 0 )
|
||
{
|
||
lp_io->state = SOCKET_STATE_CONNECT_AND_READ;
|
||
//cout<<"读取到一条数据"<<endl;
|
||
}
|
||
|
||
//取IP地址与端口信息
|
||
SOCKADDR *local=NULL;
|
||
SOCKADDR *remote=NULL;
|
||
int local_len;
|
||
int remote_len;
|
||
lp_this->lpGetAcceptExSockAddrs(lp_io->buf,0,sizeof(SOCKADDR_IN) + 16,sizeof(SOCKADDR_IN) + 16,&local,&local_len,&remote,&remote_len);
|
||
SOCKADDR_IN * pAA = ((SOCKADDR_IN *)local);
|
||
SOCKADDR_IN * pBB = ((SOCKADDR_IN *)remote);
|
||
#ifdef UNICODE
|
||
_tcscpy(lp_io->m_szIP,A2W(inet_ntoa(pBB->sin_addr)));
|
||
#else
|
||
strcpy(lp_io->m_szIP,inet_ntoa(pBB->sin_addr));
|
||
#endif
|
||
lp_io->m_lPort = ntohs(pBB->sin_port);
|
||
lp_io->m_lLocalPort = ntohs(pAA->sin_port);
|
||
#ifdef UNICODE
|
||
|
||
if (lp_io->m_lLocalPort == DEFAULT_SERVERPORT_UNI )
|
||
#else
|
||
if (lp_io->m_lLocalPort == DEFAULT_LISTENPORT )
|
||
#endif
|
||
{
|
||
nRet = setsockopt(
|
||
lp_io->socket,
|
||
SOL_SOCKET,
|
||
SO_UPDATE_ACCEPT_CONTEXT,
|
||
( char* )&lp_this->m_listen_socket,
|
||
sizeof( lp_this->m_listen_socket ) );
|
||
}
|
||
else
|
||
{
|
||
nRet = setsockopt(
|
||
lp_io->socket,
|
||
SOL_SOCKET,
|
||
SO_UPDATE_ACCEPT_CONTEXT,
|
||
( char* )&lp_this->m_listen_socket2,
|
||
sizeof( lp_this->m_listen_socket2 ) );
|
||
}
|
||
|
||
if( SOCKET_ERROR == nRet )
|
||
{
|
||
closesocket( lp_io->socket );
|
||
//lp_this->m_io_group.RemoveAt( lp_io );
|
||
lp_this->m_KeyList.RemoveAt_IO( lp_io );
|
||
//cout<<"update socket fail!"<<WSAGetLastError()<<endl;
|
||
continue;
|
||
}
|
||
//lp_new_key = lp_this->m_key_group.GetBlank();
|
||
lp_new_key = lp_this->m_KeyList.GetBlank_Key();
|
||
if( lp_new_key == NULL )
|
||
{
|
||
closesocket( lp_io->socket );
|
||
continue;
|
||
}
|
||
|
||
lp_new_key->socket = lp_io->socket;
|
||
lp_io->pKey = lp_new_key; //记录对应的key参数
|
||
lp_io->dwAcceptTime = ::GetTickCount(); //Accept的时间
|
||
|
||
//将新建立的SOCKET同完成端口关联起来。
|
||
hRet = CreateIoCompletionPort(
|
||
( HANDLE )lp_io->socket,
|
||
lp_this->m_h_iocp,
|
||
(ULONG_PTR)lp_new_key,0 );
|
||
if( NULL == hRet )
|
||
{
|
||
lp_this->m_KeyList.RemoveAt_Key( lp_new_key );
|
||
lp_this->m_KeyList.RemoveAt_IO( lp_io );
|
||
closesocket( lp_io->socket );
|
||
continue;
|
||
}
|
||
|
||
//处理数据
|
||
lp_this->HandleData( lp_io, lp_new_key,IOCP_COMPLETE_ACCEPT );
|
||
|
||
bRet = lp_this->DataAction( lp_io, lp_new_key );
|
||
|
||
if( FALSE == bRet )
|
||
{
|
||
continue;
|
||
}
|
||
}
|
||
break;
|
||
case IOCP_READ:
|
||
{
|
||
if( SOCKET_STATE_CONNECT_AND_READ != lp_io->state )
|
||
{
|
||
lp_io->state = SOCKET_STATE_CONNECT_AND_READ;
|
||
}
|
||
|
||
lp_io->wsaBuf.len = dwBytes;
|
||
|
||
lp_this->HandleData( lp_io, lp_key, IOCP_COMPLETE_READ );
|
||
|
||
bRet = lp_this->DataAction( lp_io, lp_key );
|
||
|
||
if( FALSE == bRet )
|
||
{
|
||
continue;
|
||
}
|
||
}
|
||
break;
|
||
case IOCP_WRITE:
|
||
{
|
||
lp_this->HandleData( lp_io, lp_key, IOCP_COMPLETE_WRITE );
|
||
|
||
|
||
if( FALSE == bRet )
|
||
{
|
||
continue;
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
{
|
||
continue;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
catch (... )
|
||
{
|
||
LOG_APPERROR(_T("T"));
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
void CIOCP::CloseMainSocket()
|
||
{
|
||
CloseOneSocket(m_listen_socket);
|
||
CloseOneSocket(m_listen_socket2);
|
||
}
|
||
|
||
BOOL CIOCP::BindAndListenSocket2()
|
||
{
|
||
SOCKADDR_IN addr;
|
||
|
||
memset( &addr, 0, sizeof(SOCKADDR_IN) );
|
||
|
||
addr.sin_family = AF_INET;
|
||
//addr.sin_addr.s_addr = inet_addr( ADDR );
|
||
//addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||
addr.sin_addr.s_addr = m_pDlg->m_Setup.addr;
|
||
addr.sin_port = htons( DEFAULT_LISTENPORT2 );
|
||
|
||
|
||
int nRet;
|
||
|
||
nRet = bind( m_listen_socket2, (SOCKADDR*)&addr, sizeof( SOCKADDR ) );
|
||
|
||
if( SOCKET_ERROR == nRet )
|
||
{
|
||
//cout<<"bind fail!"<<endl;
|
||
return FALSE;
|
||
}
|
||
|
||
nRet = listen( m_listen_socket2, 20 );
|
||
|
||
if( SOCKET_ERROR == nRet )
|
||
{
|
||
//cout<<"listen fail!"<<endl;
|
||
return FALSE;
|
||
}
|
||
m_bInitSocket2 = true;
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
void CIOCP::CloseOneSocket(SOCKET &socket)
|
||
{
|
||
if ( socket != INVALID_SOCKET )
|
||
{
|
||
closesocket(socket);
|
||
socket = INVALID_SOCKET;
|
||
}
|
||
}
|
||
|
||
BOOL CIOCP::PostAcceptEx2()
|
||
{
|
||
#ifdef _DEBUG
|
||
int count = 10;
|
||
#else
|
||
int count = 30;
|
||
#endif
|
||
DWORD dwBytes;
|
||
BOOL bRet;
|
||
|
||
for( int i = 0; i < count; i++ )
|
||
{
|
||
SOCKET socket = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED );
|
||
|
||
if( INVALID_SOCKET == socket )
|
||
{
|
||
//cout<<"post accept ex fail!"<<WSAGetLastError()<<endl;
|
||
continue;
|
||
}
|
||
/*
|
||
//设置Socket
|
||
u_long ulTemp=1; //将SOCKET设成非阻塞式的SOCKET
|
||
//u_long ulTemp=0; //将SOCKET设成阻塞式的SOCKET
|
||
ioctlsocket( socket,FIONBIO,&ulTemp );
|
||
ulTemp=64000;
|
||
setsockopt( socket , SOL_SOCKET, SO_SNDBUF ,(const char *)&ulTemp ,sizeof(ulTemp)); //设绶冲
|
||
ulTemp=64000;
|
||
setsockopt( socket , SOL_SOCKET, SO_RCVBUF ,(const char *)&ulTemp ,sizeof(ulTemp)); //设绶冲
|
||
setsockopt( socket, SOL_SOCKET, SO_DONTLINGER,(const char *)&ulTemp,sizeof(BOOL));
|
||
|
||
struct linger {
|
||
u_short l_onoff;
|
||
u_short l_linger;
|
||
};
|
||
linger m_sLinger;
|
||
m_sLinger.l_onoff=0;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留)
|
||
// 如果m_sLinger.l_onoff=0;则功能和2.)作用相同;
|
||
m_sLinger.l_linger=0;//(容许逗留的时间为5秒)
|
||
int iLen=sizeof(m_sLinger);
|
||
int i = setsockopt(socket,SOL_SOCKET,SO_LINGER,(const char*)&m_sLinger,sizeof(linger));
|
||
*/
|
||
|
||
//IOCP_IO_PTR lp_io = m_io_group.GetBlank();
|
||
IOCP_IO_PTR lp_io = m_KeyList.GetBlank_IO();
|
||
|
||
if ( lp_io != NULL )
|
||
{
|
||
InitIoContext( lp_io );
|
||
lp_io->socket = socket;
|
||
lp_io->operation = IOCP_ACCEPT;
|
||
lp_io->state = SOCKET_STATE_NOT_CONNECT;
|
||
/////////////////////////////////////////////////
|
||
bRet = lpAcceptEx(
|
||
m_listen_socket2,
|
||
lp_io->socket,
|
||
lp_io->buf,
|
||
// lp_io->wsaBuf.len - 2 * ( sizeof(SOCKADDR_IN) + 16 ),
|
||
0,
|
||
sizeof(SOCKADDR_IN) + 16,
|
||
sizeof(SOCKADDR_IN) + 16,
|
||
&dwBytes,&lp_io->ol);
|
||
|
||
if( ( bRet == FALSE ) && ( WSA_IO_PENDING != WSAGetLastError() ) )
|
||
{
|
||
closesocket( socket );
|
||
|
||
//m_io_group.RemoveAt( lp_io );
|
||
m_KeyList.RemoveAt_IO( lp_io );
|
||
|
||
//cout<<"post acceptex fail:"<<WSAGetLastError()<<endl;
|
||
continue;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
int i=10;
|
||
}
|
||
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
BOOL CIOCP::RegAcceptEvent2()
|
||
{
|
||
int nRet;
|
||
|
||
m_h_accept_event2 = CreateEvent( NULL, FALSE, FALSE, NULL );
|
||
|
||
if( NULL == m_h_accept_event2 )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
nRet = WSAEventSelect( m_listen_socket2, m_h_accept_event2, FD_ACCEPT );
|
||
|
||
if( nRet != 0 )
|
||
{
|
||
CloseHandle( m_h_accept_event2 );
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
long CIOCP::GetFrame(IOCP_IO_PTR lp_io)
|
||
{
|
||
try
|
||
{
|
||
int iGetFrame=0;
|
||
for ( int i=0 ; i<lp_io->lRecvLen ; i++ )
|
||
{
|
||
if ( i+sizeof(Socket_Head) > (DWORD)lp_io->lRecvLen )
|
||
{
|
||
//i--;
|
||
break;
|
||
}
|
||
Socket_Head SHead={0};
|
||
memcpy(&SHead,lp_io->buf+i,sizeof(Socket_Head)); i=i+sizeof(Socket_Head);
|
||
long lGetLen=SHead.lFrameLen;
|
||
if ( SHead.bCompress )
|
||
lGetLen = SHead.lCompressLen;
|
||
if ( SHead.lFuncType <=0 || SHead.lFuncType > 100000 ||
|
||
SHead.lCompressLen<0 || SHead.lCompressLen>BUFFER_SIZE ||
|
||
SHead.lFrameLen<0 || SHead.lFrameLen>BUFFER_SIZE ) //简单判断收到的帧是否有问题
|
||
{
|
||
return -1; //数据不对,关闭连接
|
||
}
|
||
if ( i+lGetLen>lp_io->lRecvLen) //数据不够
|
||
{
|
||
i=i-sizeof(Socket_Head);
|
||
//i--;
|
||
break;
|
||
}
|
||
lp_io->dwEndRecvFrame = ::GetTickCount();
|
||
|
||
|
||
if ( SHead.lFuncType == SMSFUNC_TEST && lp_io->m_lUserID>0 ) //直接回复SMSFunc_Test
|
||
{
|
||
ANS_Test * pTestRet = new ANS_Test;
|
||
pTestRet->lTemp = ::GetTickCount();
|
||
CSmsCenterDlg::SendFrame(lp_io, SMSFUNC_TEST , (BYTE*)pTestRet , sizeof(ANS_Test) ); //发送返回
|
||
}
|
||
else
|
||
{
|
||
IOCP_SQL_PTR pSql = m_KeyList.GetBlank_SQL();
|
||
if ( pSql )
|
||
{
|
||
try
|
||
{
|
||
//CProcessSocket * pProcess = m_KeyList.GetBlank_Process();
|
||
CProcessSocket * pProcess = new CProcessSocket;
|
||
if ( pProcess )
|
||
{
|
||
BOOL bOK = true;
|
||
|
||
pProcess->SetDlg(m_pDlg);
|
||
pProcess->IOCP_setSQL(pSql);
|
||
|
||
Cmpp_Head head={0};
|
||
bOK = pProcess->IOCP_GetFrameData(lp_io , SHead , head,(BYTE*)(lp_io->buf+i) , lGetLen);
|
||
if ( bOK ) //启动线程处理
|
||
{
|
||
iGetFrame ++;
|
||
QueueUserWorkItem(CProcessSocket::IOCP_Process, (PVOID)pProcess, WT_EXECUTELONGFUNCTION);
|
||
}
|
||
else
|
||
{
|
||
//释放资源
|
||
pProcess->m_bUse = false;
|
||
pProcess->m_lRandID=0;
|
||
|
||
pSql->bUse = false;
|
||
pSql->lRandID = 0;
|
||
//暂时不删除此对像,防止出错
|
||
delete pProcess; //删除new的对像
|
||
}
|
||
}
|
||
else
|
||
{
|
||
AfxMessageBox(_T("new Process error"));
|
||
}
|
||
}
|
||
catch(...)
|
||
{
|
||
LOG_APPERROR(_T("T"));
|
||
pSql->bUse = false; //有异常,恢复正常模式
|
||
pSql->lRandID = 0;
|
||
}
|
||
}
|
||
}
|
||
i=i+lGetLen;
|
||
i=i-1;
|
||
}
|
||
if ( i >= lp_io->lRecvLen ) //数据刚刚好
|
||
{
|
||
lp_io->lRecvLen = 0;
|
||
}
|
||
else
|
||
{
|
||
if ( i> 0 )
|
||
{
|
||
//转移数据
|
||
lp_io->lRecvLen = lp_io->lRecvLen-i;
|
||
memcpy(lp_io->buf , lp_io->buf+i , lp_io->lRecvLen );
|
||
}
|
||
}
|
||
|
||
return iGetFrame;
|
||
}
|
||
catch (...)
|
||
{
|
||
LOG_APPERROR(_T("T"));
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
|
||
long CIOCP::GetFrame_Cmpp(IOCP_IO_PTR lp_io)
|
||
{
|
||
try
|
||
{
|
||
int iGetFrame=0;
|
||
for ( int i=0 ; i<lp_io->lRecvLen ; i++ )
|
||
{
|
||
if ( i+sizeof(Cmpp_Head) > (DWORD)lp_io->lRecvLen )
|
||
{
|
||
//i--;
|
||
break;
|
||
}
|
||
Cmpp_Head SHead={0};
|
||
memcpy(&SHead,lp_io->buf+i,sizeof(Cmpp_Head)); i=i+sizeof(Cmpp_Head);
|
||
SHead.Command_Id = ntohl(SHead.Command_Id);
|
||
SHead.Sequence_Id= ntohl(SHead.Sequence_Id);
|
||
SHead.Total_Length = ntohl(SHead.Total_Length);
|
||
long lGetLen=SHead.Total_Length-sizeof(Cmpp_Head);
|
||
if ( SHead.Total_Length <=0 || SHead.Total_Length>BUFFER_SIZE ) //简单判断收到的帧是否有问题
|
||
{
|
||
return -1; //数据不对,关闭连接
|
||
}
|
||
if ( i+lGetLen>lp_io->lRecvLen) //数据不够
|
||
{
|
||
i=i-sizeof(Cmpp_Head);
|
||
//i--;
|
||
break;
|
||
}
|
||
lp_io->dwEndRecvFrame = ::GetTickCount();
|
||
|
||
/*
|
||
if ( SHead.Command_Id == CMPP_ACTIVE_TEST && lp_io->m_lUserID>0 ) //直接回复SMSFunc_Test
|
||
{
|
||
Cmpp_Active_Test_Resp * pActive = new Cmpp_Active_Test_Resp;
|
||
memset(pActive , 0 , sizeof(Cmpp_Active_Test_Resp));
|
||
CSmsCenterDlg::SendFrame_Cmpp(lp_io, CMPP_ACTIVE_TEST_RESP ,SHead.Sequence_Id, (BYTE*)pActive , sizeof(Cmpp_Active_Test_Resp) ); //发送返回
|
||
}
|
||
else
|
||
{
|
||
IOCP_SQL_PTR pSql = m_KeyList.GetBlank_SQL();
|
||
if ( pSql )
|
||
{
|
||
//CProcessSocket * pProcess = m_KeyList.GetBlank_Process();
|
||
CProcessSocket * pProcess = new CProcessSocket;
|
||
if ( pProcess )
|
||
{
|
||
BOOL bOK = true;
|
||
|
||
pProcess->SetDlg(m_pDlg);
|
||
pProcess->IOCP_setSQL(pSql);
|
||
|
||
Socket_Head head={0};
|
||
bOK = pProcess->IOCP_GetFrameData(lp_io , head,SHead , (BYTE*)(lp_io->buf+i) , lGetLen);
|
||
if ( bOK ) //启动线程处理
|
||
{
|
||
iGetFrame ++;
|
||
QueueUserWorkItem(CProcessSocket::IOCP_Process, (PVOID)pProcess, WT_EXECUTELONGFUNCTION);
|
||
}
|
||
else
|
||
{
|
||
//释放资源
|
||
pProcess->m_bUse = false;
|
||
pProcess->m_lRandID=0;
|
||
|
||
pSql->bUse = false;
|
||
pSql->lRandID = 0;
|
||
//暂时不删除此对像,防止出错
|
||
delete pProcess; //删除new的对像
|
||
}
|
||
}
|
||
}
|
||
}
|
||
*/
|
||
i=i+lGetLen;
|
||
i=i-1;
|
||
}
|
||
if ( i >= lp_io->lRecvLen ) //数据刚刚好
|
||
{
|
||
lp_io->lRecvLen = 0;
|
||
}
|
||
else
|
||
{
|
||
if ( i> 0 )
|
||
{
|
||
//转移数据
|
||
lp_io->lRecvLen = lp_io->lRecvLen-i;
|
||
memcpy(lp_io->buf , lp_io->buf+i , lp_io->lRecvLen );
|
||
}
|
||
}
|
||
|
||
return iGetFrame;
|
||
}
|
||
catch (...)
|
||
{
|
||
LOG_APPERROR(_T("T"));
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
void CIOCP::SetDlg(CSmsCenterDlg *pDlg)
|
||
{
|
||
m_pDlg = pDlg;
|
||
}
|
||
|
||
void CIOCP::InitIoContext_Send(IOCP_IO_SEND_PTR lp_io)
|
||
{
|
||
memset( &lp_io->ol, 0, sizeof( WSAOVERLAPPED ) );
|
||
}
|
||
|
||
void CIOCP::CheckForInvalidSQLConnection()
|
||
{
|
||
try
|
||
{
|
||
TCHAR szMsg[256]={0};
|
||
DWORD dwNow = ::GetTickCount();
|
||
/*
|
||
LPVOID * lpProcess = m_KeyList.m_Process;
|
||
if ( lpProcess )
|
||
{
|
||
for ( int i=0 ; i<MAX_SQLCONNECT; i++ )
|
||
{
|
||
CProcessSocket * pSocket = (CProcessSocket *)lpProcess[i];
|
||
if ( pSocket && pSocket->m_adoConnection.IsOpen() )
|
||
{
|
||
if ( pSocket->m_bUse && pSocket->m_lRandID>0 ) //在使用中的SQL,40分钟超时
|
||
{
|
||
if ( dwNow - pSocket->m_dwEndUse > SQL_TIMEOUT_USE )
|
||
{
|
||
pSocket->m_AdoRS.Close();
|
||
pSocket->m_AdoRS2.Close();
|
||
pSocket->m_adoConnection.Close();
|
||
pSocket->m_bUse = false;
|
||
pSocket->m_lRandID = 0;
|
||
|
||
sprintf(szMsg, "SQL:%d 操作超时,自动断连!" , i );
|
||
m_pDlg->AddLog(szMsg);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//不在使用中的SQL,20分钟超时
|
||
if ( dwNow - pSocket->m_dwEndUse > SQL_TIMEOUT_DISUSE )
|
||
{
|
||
pSocket->m_AdoRS.Close();
|
||
pSocket->m_AdoRS2.Close();
|
||
pSocket->m_adoConnection.Close();
|
||
pSocket->m_bUse = false;
|
||
pSocket->m_lRandID = 0;
|
||
|
||
sprintf(szMsg, "SQL:%d 超时未使用,自动断连!" , i );
|
||
m_pDlg->AddLog(szMsg);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
*/
|
||
IOCP_SQL_PTR pSql = m_KeyList.m_SQL;
|
||
if ( pSql )
|
||
{
|
||
for ( int i=0 ; i<MAX_SQLCONNECT; i++ )
|
||
{
|
||
if ( pSql[i].adoConnection.IsOpen() )
|
||
{
|
||
if ( pSql[i].bUse && pSql[i].lRandID>0 ) //在使用中的SQL,40分钟超时
|
||
{
|
||
if ( dwNow - pSql[i].dwEndUse > SQL_TIMEOUT_USE )
|
||
{
|
||
pSql[i].adoConnection.Close();
|
||
pSql[i].bUse = false;
|
||
pSql[i].lRandID = 0;
|
||
|
||
_stprintf(szMsg, _T("SQL:%d 操作超时,自动断连!") , i );
|
||
m_pDlg->AddLog(szMsg);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//不在使用中的SQL,20分钟超时
|
||
if ( dwNow - pSql[i].dwEndUse > SQL_TIMEOUT_DISUSE )
|
||
{
|
||
pSql[i].adoConnection.Close();
|
||
pSql[i].bUse = false;
|
||
pSql[i].lRandID = 0;
|
||
|
||
_stprintf(szMsg, _T("SQL:%d 超时未使用,自动断连!") , i );
|
||
m_pDlg->AddLog(szMsg);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (...)
|
||
{
|
||
LOG_APPERROR(_T("T"));
|
||
}
|
||
}
|
||
|
||
DWORD WINAPI CIOCP::MainLoop2(LPVOID lp_param)
|
||
{
|
||
try
|
||
{
|
||
AutoCoInitializeEx AutoCoInit; //自动初始化与结束Com环境
|
||
|
||
CIOCP * piocp = (CIOCP *)lp_param;
|
||
|
||
int nCount = 0;
|
||
int nCount2= 0;
|
||
while( !piocp->m_bQuit )
|
||
{
|
||
nCount ++;
|
||
if ( nCount>10 ) //每5秒检测一次超时
|
||
{
|
||
nCount=0;
|
||
piocp->CheckForInvalidConnection();
|
||
}
|
||
nCount2 ++;
|
||
if ( nCount2>120 ) //每1分钟检测一次超时
|
||
{
|
||
nCount2=0;
|
||
piocp->CheckForInvalidSQLConnection();
|
||
}
|
||
Sleep(500);
|
||
}
|
||
return TRUE;
|
||
}
|
||
catch(...)
|
||
{
|
||
LOG_APPERROR(_T("T"));
|
||
return false;
|
||
}
|
||
}
|