#include "StdAfx.h" #include "IServerImpl.h" #include #include #include #include "ThreadPool.hpp" #include "ClientProcess.h" // #ifdef _DEBUG // #define new DEBUG_NEW // #endif const int AF_IPV4 = 0; const int AF_IPV6 = 1; const int SOCK_TCP = SOCK_STREAM-1; const int SOCK_UDP = SOCK_DGRAM-1; namespace ServerSocketImpl { IServerImpl* g_pServerSocket[20] = {0}; IServerImpl::IServerImpl():m_nMode(AF_IPV4) ,m_nSockType(SOCK_TCP) ,m_strPort(_T("64320")) ,m_nSocketIndex(0) { m_bStopbeat = FALSE; m_hRunObject = NULL; m_hClearInvalidateSocketThread = NULL; InitializeCriticalSection( &m_csProcessData ); m_SocketServer.SetInterface(this); } IServerImpl::~IServerImpl() { m_SocketServer.Terminate(); DeleteCriticalSection( &m_csProcessData ); } BOOL IServerImpl::Initialize() { TCHAR szIPAddr[MAX_PATH] = { 0 }; CSocketHandle::GetLocalAddress(szIPAddr, MAX_PATH, AF_INET); //AppendText(_T("Local Address (IPv4): %s\r\n"), szIPAddr); CSocketHandle::GetLocalAddress(szIPAddr, MAX_PATH, AF_INET6); //AppendText(_T("Local Address (IPv6): %s\r\n"), szIPAddr); return TRUE; } void IServerImpl::Start(IN LPCTSTR strPort,IN const int &nMode) { m_nMode = nMode; int nFamily = (m_nMode == AF_IPV4) ? AF_INET : AF_INET6; if (!m_SocketServer.StartServer(NULL, strPort, nFamily, (m_nSockType+1))) { //OutputDebugString(_T("\n连接服务器失败!\n")); AfxMessageBox(_T("Failed to start server."), NULL, MB_ICONSTOP); return; } CClientProcess::GetInstance()->StartMsgWork(); //SyncControls(); } void IServerImpl::Stop() { if(m_hRunObject) SetEvent(m_hRunObject); if( m_hClearInvalidateSocketThread ) { if (WaitForSingleObject(m_hClearInvalidateSocketThread,INFINITE) != WAIT_FAILED) { CloseHandle(m_hClearInvalidateSocketThread); m_hClearInvalidateSocketThread = NULL; } } if ( m_hRunObject ) CloseHandle( m_hRunObject ); m_hRunObject = NULL; m_SocketServer.Terminate(); //SyncControls(); } void IServerImpl::Send() { if ( m_SocketServer.IsOpen() ) { CString strMsg; //m_ctlMessage.GetWindowText( strMsg ); if ( strMsg.IsEmpty() ) { //AppendText( _T("Please enter the message to send.\r\n") ); return; } USES_CONVERSION; if (m_nSockType == SOCK_TCP) { const LPBYTE lpbData = (const LPBYTE)(T2CA(strMsg)); // unsafe access to Socket list! #ifdef SOCKHANDLE_USE_OVERLAPPED const SocketContextList& sl = m_SocketServer.GetSocketList(); for(SocketContextList::const_iterator citer = sl.begin(); citer != sl.end(); ++citer) #else const SocketList& sl = m_SocketServer.GetSocketList(); for(SocketList::const_iterator citer = sl.begin(); citer != sl.end(); ++citer) #endif { CSocketHandle sockHandle; sockHandle.Attach( (*citer) ); sockHandle.Write(lpbData, strMsg.GetLength(), NULL); sockHandle.Detach(); } } else { SockAddrIn servAddr, sockAddr; m_SocketServer->GetSockName(servAddr); GetDestination(sockAddr); if ( servAddr != sockAddr ) { m_SocketServer.Write((const LPBYTE)(T2CA(strMsg)), strMsg.GetLength(), sockAddr); } else { //AppendText( _T("Please change the port number to send message to a client.\r\n") ); } } } else { AfxMessageBox(_T("Socket is not connected")); } } void IServerImpl::SendAll(CSocketHandle &sockHandle, unsigned char *pMsg, int nLength) { if ( m_SocketServer.IsOpen() ) { USES_CONVERSION; if (m_nSockType == SOCK_TCP) { // unsafe access to Socket list! const LPBYTE lpbData = (const LPBYTE)(pMsg); sockHandle.Write(lpbData, nLength, NULL); } else { SockAddrIn servAddr, sockAddr; m_SocketServer->GetSockName(servAddr); GetDestination(sockAddr); if ( servAddr != sockAddr ) { m_SocketServer.Write((const LPBYTE)*pMsg, nLength, sockAddr); } else { } } } else { } } void IServerImpl::ToprocessRecivebuf(IN PerSocketContext &sockHandle, IN const BYTE* pReceivebuf, IN DWORD dwReceiveSize) { } int IServerImpl::OnIntegrityPacket(IN PerSocketContext &sockHandle, IN void *pIntegrityPacket) { return 0; } void IServerImpl::GetAddress(const SockAddrIn& addrIn, CString& rString) const { TCHAR szIPAddr[MAX_PATH] = { 0 }; CSocketHandle::FormatIP(szIPAddr, MAX_PATH, addrIn); rString.Format(_T("%s : %d"), szIPAddr, static_cast(static_cast(ntohs(addrIn.GetPort()))) ); } void IServerImpl::AppendText(LPCTSTR lpszFormat, ...) { // if ( !::IsWindow(m_ctlMsgList.GetSafeHwnd()) ) return; // TCHAR szBuffer[512]; // HWND hWnd = m_ctlMsgList.GetSafeHwnd(); // DWORD dwResult = 0; // if (SendMessageTimeout(hWnd, WM_GETTEXTLENGTH, 0, 0, SMTO_NORMAL, 500L, &dwResult) != 0) // { // int nLen = (int) dwResult; // if (SendMessageTimeout(hWnd, EM_SETSEL, nLen, nLen, SMTO_NORMAL, 500L, &dwResult) != 0) // { // size_t cb = 0; // va_list args; // va_start(args, lpszFormat); // ::StringCchVPrintfEx(szBuffer, 512, NULL, &cb, 0, lpszFormat, args); // va_end(args); // SendMessageTimeout(hWnd, EM_REPLACESEL, FALSE, reinterpret_cast(szBuffer), SMTO_NORMAL, 500L, &dwResult); // } // } } bool IServerImpl::GetDestination(SockAddrIn& addrIn) const { CString strPort; //GetDlgItemText(IDC_SVR_PORT, strPort); int nFamily = (m_nMode == AF_IPV4) ? AF_INET : AF_INET6; return addrIn.CreateFrom(NULL, strPort, nFamily); } bool IServerImpl::SetupMCAST() { const TCHAR szIPv4MCAST[] = TEXT("239.121.1.2"); const TCHAR szIPv6MCAST[] = TEXT("FF02:0:0:0:0:0:0:1"); // All Nodes local address bool result = false; if ( m_nSockType == SOCK_UDP ) { if ( m_nMode == AF_IPV4 ) { result = m_SocketServer->AddMembership(szIPv4MCAST, NULL); } else { result = m_SocketServer->AddMembership(szIPv6MCAST, NULL); HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); hr = hr; } } return result; } /////////////////////////////////////////////////////////////////////////////// void IServerImpl::OnThreadBegin(CSocketHandle* pSH) { ASSERT( pSH == m_SocketServer ); (pSH); CString strAddr; SockAddrIn sockAddr; m_SocketServer->GetSockName(sockAddr); GetAddress( sockAddr, strAddr ); //AppendText( _T("Server Running on: %s\r\n"), strAddr); } void IServerImpl::OnThreadExit(CSocketHandle* pSH) { ASSERT( pSH == m_SocketServer ); (pSH); //AppendText( _T("Server Down!\r\n")); } void IServerImpl::OnConnectionFailure(CSocketHandle* pSH, SOCKET newSocket) { ASSERT( pSH == m_SocketServer ); (pSH); CString strAddr; CSocketHandle sockHandle; SockAddrIn sockAddr; if (newSocket != INVALID_SOCKET) { sockHandle.Attach( newSocket ); sockHandle.GetPeerName( sockAddr ); GetAddress( sockAddr, strAddr ); sockHandle.Close(); //AppendText( _T("Connection abandoned: %s\r\n"), strAddr ); //LOG4C_NO_FILENUM((LOG_NOTICE,"Connection abandoned:%s",strAddr)); //OutputDebugString(_T("\n客户端连接中断:")); //OutputDebugString(strAddr); //OutputDebugString(_T("\n\n")); } else { //OutputDebugString(_T("\n客户端连接中断,不是一个有效的套接字:")); //OutputDebugString(strAddr); //OutputDebugString(_T("\n\n")); //AppendText( _T("Connection abandoned. Not a valid socket.\r\n"), strAddr ); //LOG4C_NO_FILENUM((LOG_NOTICE,"Connection abandoned. Not a valid socket:%s",strAddr)); } } void IServerImpl::OnAddConnection(CSocketHandle* pSH, SOCKET newSocket) { ASSERT( pSH == m_SocketServer ); (pSH); CString strAddr; CSocketHandle sockHandle; SockAddrIn sockAddr; sockHandle.Attach( newSocket ); sockHandle.GetPeerName( sockAddr ); GetAddress( sockAddr, strAddr ); sockHandle.Detach(); //OutputDebugString(_T("\n新的连接接入:")); //OutputDebugString(strAddr); //OutputDebugString(_T("\n")); //LOG4C_NO_FILENUM((LOG_NOTICE,"新的连接接入:%s",strAddr)); //AppendText( _T("Connection established: %s\r\n"), strAddr ); } void IServerImpl::OnDataReceived(CSocketHandle* pSH, const SOCKET sClient, const BYTE* pbData, DWORD dwCount, const SockAddrIn& addr, BYTE **pendingbuf, unsigned int& npendingSize, unsigned int& ncursize) { ASSERT( pSH == m_SocketServer ); (pSH); CString strAddr, strText; //USES_CONVERSION; //LPTSTR pszText = strText.GetBuffer(dwCount+1); //::StringCchCopyN(pszText, dwCount+1, A2CT(reinterpret_cast(pbData)), dwCount); //strText.ReleaseBuffer(); GetAddress( addr, strAddr ); //AppendText( _T("%s>(%s)\r\n"), strAddr, strText); const SocketContextList& sl = m_SocketServer.GetClientSocketList(); CClientProcess::GetInstance()->ClientProcess(sClient, pbData, dwCount, strAddr, pendingbuf, npendingSize, ncursize); } void IServerImpl::OnConnectionDropped(CSocketHandle* pSH) { ASSERT( pSH == m_SocketServer ); (pSH); CString strAddr; CSocketHandle sockHandle; SockAddrIn sockAddr; //sockHandle.Attach( pSH->GetSocket() ); sockHandle.GetPeerName( sockAddr ); GetAddress( sockAddr, strAddr ); //sockHandle.Detach(); //AppendText( _T("Connection lost with client.\r\n") ); //LOG4C_NO_FILENUM((LOG_NOTICE,"Connection lost with client")); } void IServerImpl::OnConnectionError(CSocketHandle* pSH, DWORD dwError) { ASSERT( pSH == m_SocketServer ); (pSH); _com_error err(dwError); //AppendText( _T("Communication Error:\r\n%s\r\n"), err.ErrorMessage() ); CString strAddr; CSocketHandle sockHandle; SockAddrIn sockAddr; sockHandle.GetPeerName( sockAddr ); GetAddress( sockAddr, strAddr ); //LOG4C((LOG_NOTICE,"IP:%s Communication Error:%s", strAddr, err.ErrorMessage())); } #if defined(SOCKHANDLE_USE_OVERLAPPED) void IServerImpl::OnRemoveConnection(CSocketHandle* pSH, SOCKET dropSocket) { return; ASSERT( pSH == m_SocketServer ); (pSH); CString strAddr; CSocketHandle sockHandle; SockAddrIn sockAddr; sockHandle.Attach( dropSocket ); sockHandle.GetPeerName( sockAddr ); GetAddress( sockAddr, strAddr ); sockHandle.Detach(); //LOG4C_NO_FILENUM((LOG_NOTICE,"Connection abandoned. Not a valid socket:%s",strAddr)); } #endif DWORD IServerImpl::GetClientConnectCount() { //DWORD dwClientSize = 0; //m_SocketServer->GetConnectionCount(); return m_SocketServer.GetConnectionCount(); } void IServerImpl::StartClearInvalidateSocketThread() { m_hRunObject = CreateEvent( NULL, TRUE, FALSE, _T("ClearInvalidateSocketThread") ); if ( m_hRunObject == NULL ) { // LOG4C((LOG_NOTICE,"创建事件失败")); } m_hClearInvalidateSocketThread = CreateThread(NULL,0,ClearInvalidateSocketThread,this,0,NULL); if ( m_hClearInvalidateSocketThread == NULL ) { // LOG4C((LOG_NOTICE,"创建线程失败")); } } DWORD WINAPI IServerImpl::ClearInvalidateSocketThread(void *pInstance) { //LOG4C((LOG_NOTICE,"服务端心跳检测线程")); IServerImpl *pServerImpl = (IServerImpl*)pInstance; #ifdef SOCKHANDLE_USE_OVERLAPPED /*const*/ SocketContextList& sl = pServerImpl->m_SocketServer.GetClientSocketList(); SocketContextList::iterator citer = sl.begin(); #else /*const*/ SocketList& sl = pServerImpl->m_SocketServer.GetClientSocketList(); SocketList::const_iterator citer = sl.begin(); #endif //SockAddrIn sockAddr; //size_t nSize = sl.size(); DWORD dwError; //CSocketHandle tSocketHandle; do { //nSize = sl.size(); if ( !pServerImpl->m_bStopbeat ) { //AutoThreadSection aSenction(pServerImpl->m_SocketServer.ReturnSection()); //if( (nSize != 0) && (citer != sl.end())) if ( citer != sl.end()) { //SocketIOBuffer *buf = citer; DWORD dwTick = GetTickCount(); //if ( ( dwTick - citer->dwTime) > 5000 ) //{ SOCKET sokt = static_cast(*citer++); WORD wMessageId = MSG_LOGIN_RESP; LOGIN_RESULT_STRU tLoginResult = {0}; tLoginResult.tCommonMsg.dwConnectionID = 0; tLoginResult.tCommonMsg.wMessageId = wMessageId; tLoginResult.byResult = LOGIN_RESULT_SUC; tLoginResult.dwUserID = 0; tLoginResult.byStatus = USER_STATUS_ONLINE ; DWORD dwDataLen = sizeof(LOGIN_RESULT_STRU); TMessageHeader tHeader = {0}; tHeader.wMessageId = wMessageId; tHeader.dwDataLen = dwDataLen; CSocketHandle hClient; hClient.Attach(sokt); INT nRet = CClientProcess::net_Send(&hClient, &tHeader, (void *)&tLoginResult, dwDataLen); hClient.Detach(); if ( nRet <= 0 ) { pServerImpl->m_SocketServer.RemoveConnection(sokt); pServerImpl->m_SocketServer.CloseConnection(sokt); } //} //else //{ // citer++; //} //tSocketHandle.Attach( (*citer) ); #if 0 //tSocketHandle.Write(LPBYTE("0"), 1, NULL, 30000); // 心跳包超时值:30秒到1分钟为好! dwError = WSAGetLastError(); switch( dwError ) { case WSAENOTSOCK: case WSAENETDOWN: case WSAENETUNREACH: case WSAENETRESET: case WSAECONNABORTED: case WSAECONNRESET: case WSAESHUTDOWN: case WSAEHOSTDOWN: case WSAEHOSTUNREACH: //citer = sl.erase(citer); LOG4C_NO_FILENUM((LOG_NOTICE,"删除过期客户端连接")); //pServerImpl->m_SocketServer.CloseConnection(*citer); //pServerImpl->m_SocketServer.RemoveConnection(*citer); citer = sl.begin(); default: //TRACE("--------------%d\r\n",dwError); if( citer != sl.end() ) citer++; break; } #endif //tSocketHandle.Detach(); } else if ( citer == sl.end() ) { citer = sl.begin(); } } } while (WaitForSingleObject(pServerImpl->m_hRunObject,5000L) == WAIT_TIMEOUT); return 0; } };