www.pudn.com > XYNetSocket.zip > ClientObj.cpp
// ClientObj.cpp : Implementation of CClientObj #include "stdafx.h" #include "XYNetComClient.h" #include "ClientObj.h" #includeCRITICAL_SECTION cs; void WCharToChar(char* pTarget, const unsigned short* pSource) { while(*pSource) { *pTarget = (char)(*pSource); pSource++; pTarget++; } *pTarget = 0; } void StringToBinary(BYTE* pTarget, const unsigned short* pSource, int nSize) { for(int i=0;i =0) { pThreads[nInitIndex] = ::GetCurrentThreadId(); WORD wVersionRequested = MAKEWORD(2, 0); WSADATA wsaData; if(::WSAStartup(wVersionRequested,&wsaData)!=0) { m_sError = ::SysAllocString(L"Failed to call WSAStartup"); m_nErrorCode = ::GetLastError(); ::LeaveCriticalSection(&cs); *pOutput = FALSE; return S_OK; } if(LOBYTE(wsaData.wVersion)<2) { m_sError = ::SysAllocString(L"Invalid winsock version"); m_nErrorCode = ::GetLastError(); *pOutput = FALSE; ::LeaveCriticalSection(&cs); return S_OK; } } ::LeaveCriticalSection(&cs); Reset(); if(sRemoteAddress!=NULL) { if(m_sRemoteAddress!=NULL) ::SysFreeString(m_sRemoteAddress); m_sRemoteAddress = ::SysAllocString(sRemoteAddress); } if(nRemotePort>0) m_nRemotePort = nRemotePort; m_socket = ::socket(AF_INET,SOCK_STREAM,0); if(m_socket==INVALID_SOCKET) { m_sError = ::SysAllocString(L"Failed to create socket"); m_nErrorCode = ::GetLastError(); *pOutput = FALSE; return S_OK; } else { int nLen = wcslen(m_sRemoteAddress); char* pServerAddress; if(nLen>0) { pServerAddress = new char[nLen+1]; WCharToChar(pServerAddress,m_sRemoteAddress); } else { nLen = MAX_COMPUTERNAME_LENGTH+1; pServerAddress = new char[nLen]; ::GetComputerNameA(pServerAddress,(DWORD*)&nLen); } SOCKADDR_IN sockAddr; memset(&sockAddr,0,sizeof(sockAddr)); sockAddr.sin_family = AF_INET; DWORD lResult = inet_addr(pServerAddress); if(lResult==INADDR_NONE) { LPHOSTENT lphost; lphost = gethostbyname(pServerAddress); if(lphost!=NULL) { sockAddr.sin_addr.s_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr; } else { m_sError = ::SysAllocString(L"Failed to get host name"); m_nErrorCode = ::GetLastError(); delete []pServerAddress; *pOutput = FALSE; return S_OK; } } else { sockAddr.sin_addr.s_addr = lResult; } delete []pServerAddress; sockAddr.sin_port = htons((u_short)m_nRemotePort); if(::connect(m_socket,(SOCKADDR*)&sockAddr,sizeof(sockAddr))==SOCKET_ERROR) { m_sError = ::SysAllocString(L"Failed to connect to server"); m_nErrorCode = ::GetLastError(); *pOutput = FALSE; return S_OK; } } *pOutput = TRUE; return S_OK; } STDMETHODIMP CClientObj::Reset() { m_bReconnect = FALSE; if(m_socket!=INVALID_SOCKET) { BYTE pData[4] = {255, 0, 0, 0}; SendRawData(pData, 4); ::closesocket(m_socket); m_socket = INVALID_SOCKET; } m_bReconnect = TRUE; return S_OK; } BOOL CClientObj::SendRawData(BYTE *pData, long nSize) { if(m_sError!=NULL) { ::SysFreeString(m_sError); m_sError = NULL; m_nErrorCode = 0; } if(::send(m_socket,(char*)pData,nSize,0)==SOCKET_ERROR) { long nErrorCode = ::GetLastError(); BOOL bRet = FALSE; if(m_bReconnect) Connect(NULL, 0, &bRet); if(m_sError!=NULL) ::SysFreeString(m_sError); m_sError = ::SysAllocString(L"Failed to send data"); m_nErrorCode = nErrorCode; return FALSE; } else return TRUE; } STDMETHODIMP CClientObj::SendBinaryData(BYTE *pData, long nSize, BOOL *pOutput) { BYTE* pData2 = new BYTE[nSize+4]; ::memcpy(pData2, pData, nSize); pData2[0] = 1+(nSize/16777216)*16; pData2[1] = (BYTE)(nSize%256); pData2[2] = (BYTE)((nSize%65536)/256); pData2[3] = (BYTE)(nSize/65536); *pOutput = SendRawData(pData2, nSize+4); delete []pData2; return S_OK; } STDMETHODIMP CClientObj::SendStringData(BSTR sData, BOOL *pOutput) { int nLen = ::wcslen(sData); BYTE* pData = new BYTE[2*nLen+4]; StringToBinary(pData+4, sData, nLen); pData[0] = ((2*nLen)/16777216)*16; pData[1] = (BYTE)((2*nLen)%256); pData[2] = (BYTE)(((2*nLen)%65536)/256); pData[3] = (BYTE)((2*nLen)/65536); *pOutput = SendRawData(pData, 2*nLen+4); delete []pData; return S_OK; } struct ReceiveStruct { BOOL* pOutput; CClientObj* pClient; BOOL bDone; }; void WorkerProc(void* pParam) { struct ReceiveStruct* pInput = (ReceiveStruct*)pParam; if(pInput->pClient->m_pData!=NULL) { delete [](pInput->pClient->m_pData); (pInput->pClient->m_pData) = NULL; } BYTE pHeader[4]; int nTotal = 0; while(true) { int nRead = ::recv(pInput->pClient->m_socket, (char*)(pHeader+nTotal), 4-nTotal, 0); if(nRead==SOCKET_ERROR) { pInput->pClient->m_sError = ::SysAllocString(L"Failed to call recv"); pInput->pClient->m_nErrorCode = ::GetLastError(); *(pInput->pOutput) = FALSE; pInput->bDone = TRUE; return; } nTotal += nRead; if(nTotal==4) { if(pHeader[0]==2) nTotal = 0; else break; } ::Sleep(50); } if(pHeader[0]%16>1) { pInput->pClient->m_sError = ::SysAllocString(L"Invalid data type byte"); *(pInput->pOutput) = FALSE; pInput->bDone = TRUE; return; } pInput->pClient->m_bIsBinary = ((pHeader[0]%16)==1); pInput->pClient->m_nSize = (pHeader[1]&0x000000FF)+(pHeader[2]&0x000000FF)*256+(pHeader[3]&0x000000FF)*65536+((pHeader[0]&0x000000FF)/16)*16777216; if((pInput->pClient->m_nSize)>(pInput->pClient->m_nMaxDataSize)) { pInput->pClient->m_nSize = 0; pInput->pClient->m_sError = ::SysAllocString(L"Data size too large"); *(pInput->pOutput) = FALSE; pInput->bDone = TRUE; return; } if(pInput->pClient->m_bIsBinary==FALSE&&((pInput->pClient->m_nSize)%2)!=0) { pInput->pClient->m_nSize = 0; pInput->pClient->m_sError = ::SysAllocString(L"Invalid string data size"); *(pInput->pOutput) = FALSE; pInput->bDone = TRUE; return; } pInput->pClient->m_pData = new BYTE[pInput->pClient->m_nSize]; nTotal = 0; while(true) { int nRead = ::recv((pInput->pClient->m_socket), (char*)(pInput->pClient->m_pData+nTotal), (pInput->pClient->m_nSize)-nTotal, 0); if(nRead==SOCKET_ERROR) { pInput->pClient->m_nSize = 0; pInput->pClient->m_sError = ::SysAllocString(L"Failed to call recv"); pInput->pClient->m_nErrorCode = ::GetLastError(); *(pInput->pOutput) = FALSE; pInput->bDone = TRUE; return; } nTotal += nRead; if(nTotal==pInput->pClient->m_nSize) break; ::Sleep(50); } *(pInput->pOutput) = TRUE; pInput->bDone = TRUE; return; } STDMETHODIMP CClientObj::ReceiveData(long *pSize, BOOL *pIsBinary, BOOL *pOutput) { if(m_sError!=NULL) { ::SysFreeString(m_sError); m_sError = NULL; m_nErrorCode = 0; } long hThread = -1; try { struct ReceiveStruct input = {pOutput, this, FALSE}; hThread = _beginthread(WorkerProc, 0, &input); if(hThread==-1) { m_sError = ::SysAllocString(L"Failed to create thread"); *pOutput = FALSE; } else { long nStart = ::GetTickCount(); while(input.bDone==FALSE) { ::Sleep(50); if(long(::GetTickCount()-nStart)>m_nReadTimeout*1000) { ::TerminateThread((HANDLE)hThread, 1); hThread = -1; if(m_sError!=NULL) ::SysFreeString(m_sError); m_sError = ::SysAllocString(L"Timeout while receiving incoming data"); break; } } if(input.bDone==FALSE) *pOutput = FALSE; else if(*pOutput) { *pSize = m_nSize; *pIsBinary = m_bIsBinary; } } } catch(...) { if(hThread!=-1) ::TerminateThread((HANDLE)hThread, 2); if(m_sError!=NULL) ::SysFreeString(m_sError); m_sError = ::SysAllocString(L"Unexpected exception while receiving incoming data"); m_nErrorCode = ::GetLastError(); *pOutput = FALSE; } if(*pOutput==FALSE) { long nErrorCode = m_nErrorCode; BSTR sError = m_sError; m_sError = NULL; BOOL bRet = FALSE; if(m_bReconnect) Connect(NULL, 0, &bRet); if(m_sError!=NULL) ::SysFreeString(m_sError); m_sError = sError; m_nErrorCode = nErrorCode; } return S_OK; } STDMETHODIMP CClientObj::GetLastError(BSTR *pOutput) { if(m_sError==NULL) *pOutput = ::SysAllocString(L""); else *pOutput = m_sError; return S_OK; } STDMETHODIMP CClientObj::GetStringData(BSTR *pOutput) { if(m_bIsBinary||(m_nSize%2!=0)||m_pData==NULL) return S_FALSE; WCHAR* pData = new WCHAR[(m_nSize/2)+1]; BinaryToString(pData, m_pData, m_nSize/2); pData[m_nSize/2] = 0; *pOutput = ::SysAllocString(pData); delete []pData; return S_OK; } STDMETHODIMP CClientObj::GetBinaryData(long* pSize, long* pData) { *pSize = m_nSize; *pData = long(m_pData); return S_OK; } STDMETHODIMP CClientObj::GetLastErrorCode(long *pOutput) { *pOutput = m_nErrorCode; return S_OK; } STDMETHODIMP CClientObj::SetReadTimeout(long nReadTimeout) { if(nReadTimeout>=5&&nReadTimeout<=120) m_nReadTimeout = nReadTimeout; return S_OK; } STDMETHODIMP CClientObj::SetMaxDataSize(long nMaxDataSize) { if(nMaxDataSize>=1024) m_nMaxDataSize = nMaxDataSize; return S_OK; }