#include "stdafx.h" #include ".\clientsocket.h" #include #include #include "modbustcp.h" //#include "Client2SrvType.h" #pragma warning(push) #pragma warning(disable:4995) #pragma warning(pop) const int AF_IPV4 = 0; const int AF_IPV6 = 1; const int SOCK_TCP = SOCK_STREAM-1; const int SOCK_UDP = SOCK_DGRAM-1; CClientSocket::CClientSocket(void) { m_nMode = AF_IPV4; m_nSockType = SOCK_TCP; m_SocketClient.SetInterface(this); m_bSocket = FALSE; #if IS_USE_EVENT MTVERIFY( m_hSemNet = CreateEvent( NULL, TRUE, TRUE, 0 ) ); #endif MTVERIFY (m_hRunObject = ::CreateEvent( NULL, /* Security */ TRUE, /* Manual event */ 0, /* Clear on creation */ "modbusTcp::m_hRunObject")); //InitializeCriticalSection( &m_csWrFinished ); } CClientSocket::~CClientSocket(void) { if( m_hRunObject != NULL ) { MTVERIFY( CloseHandle( m_hRunObject ) ); m_hRunObject = NULL; } #if IS_USE_EVENT if( m_hSemNet != NULL ) { MTVERIFY( CloseHandle( m_hSemNet )); m_hSemNet = NULL; } #endif //DeleteCriticalSection( &m_csWrFinished ); } bool CClientSocket::GetDestination(SockAddrIn& addrIn) const { CString strIPAddress, strPort; int nFamily = (m_nMode == AF_IPV4) ? AF_INET : AF_INET6; return addrIn.CreateFrom(strIPAddress, strPort, nFamily); } int CClientSocket::ClientSend(char* pMsg, int iLen) { if ( m_SocketClient.IsOpen() ) { if ( pMsg == NULL ) { return -1; } USES_CONVERSION; if (m_nSockType == SOCK_TCP) { return m_SocketClient.Write((const LPBYTE)(pMsg), iLen, NULL); } else { SockAddrIn sockAddr; GetDestination(sockAddr); m_SocketClient.Write((const LPBYTE)(pMsg), iLen, sockAddr); } } else { ;//MessageBox(_T("Socket is not connected")); } return 0; } BOOL CClientSocket::Connection(LPCTSTR strAddr, LPCTSTR strPort) { int nFamily = (m_nMode == AF_IPV4) ? AF_INET : AF_INET6; if ( !m_SocketClient.StartClient(NULL, strAddr, strPort, nFamily, (m_nSockType+1) ) ) { //MessageBox(NULL, _T("连接服务器失败!"), "提示", MB_ICONSTOP); return FALSE; } else { CSocketHandle* pSH = (CSocketHandle *)m_SocketClient; pSH->m_nPendingSize = 0; memset(pSH->m_PendingBuffer, 0, SOCKET_BUFFSIZE); SetupMCAST(); return TRUE; } } void CClientSocket::DisConnection() { m_SocketClient.Terminate(); } /////////////////////////////////////////////////////////////////////////////// // 实现ISocketClientHandler的通信方法 void CClientSocket::OnThreadBegin(CSocketHandle* pSH) { ASSERT( pSH == m_SocketClient ); (pSH); CString strAddr; SockAddrIn sockAddr; m_SocketClient->GetSockName(sockAddr); GetAddress( sockAddr, strAddr ); InitializeCriticalSection(&pSH->m_hClient2SrvSection); //AppendText( _T("Client Running on: %s\r\n"), strAddr); } void CClientSocket::OnThreadExit(CSocketHandle* pSH) { ASSERT( pSH == m_SocketClient ); DeleteCriticalSection( &pSH->m_hClient2SrvSection ); (pSH); } void CClientSocket::OnDataReceived(CSocketHandle* pSH, const BYTE* pbData, DWORD dwCount, const SockAddrIn& addr) { ASSERT( pSH == m_SocketClient ); (pSH); if( !m_SocketClient->IsOpen() ) return; //ProcessData( pSH, pbData, dwCount ); int nRet; nRet = OnCmdProcess( (void *)pbData, dwCount); if( nRet == -1 ) { TRACE("crc32 error \r\n"); } } void CClientSocket::OnConnectionDropped(CSocketHandle* pSH) { ASSERT( pSH == m_SocketClient ); (pSH); TRACE(_T("======连接服务器断开.\r\n")); m_bSocket = FALSE; } void CClientSocket::OnConnectionError(CSocketHandle* pSH, DWORD dwError) { ASSERT( pSH == m_SocketClient ); (pSH); _com_error err(dwError); m_bSocket = FALSE; } bool CClientSocket::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_SocketClient->AddMembership(szIPv4MCAST, NULL); } else { result = m_SocketClient->AddMembership(szIPv6MCAST, NULL); HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); hr = hr; } } return result; } void CClientSocket::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 CClientSocket::ProcessData(CSocketHandle *pSH, const BYTE* pData, DWORD nLen) { DWORD nBuffIndex = 0; EnterCriticalSection( &(pSH->m_hClient2SrvSection) ); while( nBuffIndex < nLen ) { //ProtocolHeader *pHeader; //当前协议包头 HEADER *pHeader; int iAllLen = 0; DWORD nProcessedLen = 0; //当前循环处理了多少个字节 if( pSH->m_nPendingSize > 0 ) // 开始组包 { pHeader = (HEADER *)pSH->m_PendingBuffer; iAllLen = htons(pHeader->ByteNum) + 6; if( pSH->m_nPendingSize < sizeof(HEADER) ) //上一次接收到的长度小于包头 { DWORD nLinkHeaderLen = sizeof( HEADER ) - pSH->m_nPendingSize; if( nLinkHeaderLen <= nLen ) //这次可以收完包头 { memcpy( &pSH->m_PendingBuffer[ pSH->m_nPendingSize ], pData, nLinkHeaderLen );//这里已经收完Header nProcessedLen = iAllLen - pSH->m_nPendingSize; if( nProcessedLen <= nLen ) //如果所需处理的长度小于等于当前包长度 { memcpy( &pSH->m_PendingBuffer[ sizeof( HEADER ) ], & ( ( char *) pData )[ nLinkHeaderLen ], iAllLen - sizeof( HEADER ) ); pSH->m_nPendingSize = 0; // 收完所需的包,置m_nPendingSize为0 } else { int nTemp = nLen - nLinkHeaderLen; //除去头剩余部分的长度 if ( nTemp > 0 ) //刚好是Header的长度,不用拷贝内存,所以这里加了>0的判断 { memcpy( &pSH->m_PendingBuffer[ sizeof( HEADER ) ], & ( ( char *) pData )[ nLinkHeaderLen ], nTemp ); } pSH->m_nPendingSize += nLen; } } else //这次还是没有收完包头, 继续Pending { memcpy( &pSH->m_PendingBuffer[ pSH->m_nPendingSize ], pData, nLen ); pSH->m_nPendingSize += nLen; nProcessedLen = nLen; } } else //Header部分已经在阻塞的缓冲区中 { nProcessedLen = iAllLen - pSH->m_nPendingSize; if ( nProcessedLen <= nLen ) //如果需要处理的长度小于现有包的长度 { memcpy( &pSH->m_PendingBuffer[ pSH->m_nPendingSize ], pData, nProcessedLen ); pSH->m_nPendingSize = 0; } else //否则要继续阻塞 { memcpy( &pSH->m_PendingBuffer[ pSH->m_nPendingSize ], pData, nLen ); pSH->m_nPendingSize += nLen; } } } else //第一次接包 { pHeader = (HEADER *)&( (unsigned char *)pData )[nBuffIndex]; iAllLen = htons(pHeader->ByteNum) + 6; if( nLen - nBuffIndex < sizeof(HEADER) ) // 没有收够包头,先记录当前收到的Buffer { //如果第一次接包就没有收够包头,认为是非法包,扔掉,就是说已处理的长度nProcessedLen = 0 pSH->m_nPendingSize = nLen - nBuffIndex; memcpy(pSH->m_PendingBuffer, pHeader, pSH->m_nPendingSize); } else { nProcessedLen = iAllLen; if( iAllLen > (int)(nLen - nBuffIndex) ) { memcpy(pSH->m_PendingBuffer, pHeader, nLen - nBuffIndex); //如果第一次接包,pHeader->nLen大于当前包的总长,认为是非法包,扔掉 if( 0 == nBuffIndex ) { //组包错误,则扔掉当前包 TRACE("iAllLen大于当前包的总长,认为是非法包,扔掉\r\n"); break; } pSH->m_nPendingSize = nLen - nBuffIndex; nProcessedLen = nLen - nBuffIndex; } else { pSH->m_nPendingSize = 0; } } } if ( nProcessedLen == 0 ) { // 没有收够包头,认为是非法包,扔掉 TRACE("没有收够包头,认为是非法包,扔掉\r\n"); break; } if ( pSH->m_nPendingSize == 0 ) { if ( iAllLen > SOCKET_BUFFSIZE ) { // 包长度超过限制 TRACE("pHeader->nLen超过限制\r\n"); } if(-1 == OnCmdProcess( pHeader, nLen)) { //MessageBox( NULL, "Error OnCmdProcess", NULL, MB_OK ); TRACE("crc校验错误!\r\n"); break; } } nBuffIndex += nProcessedLen; } LeaveCriticalSection( &(pSH->m_hClient2SrvSection) ); } int CClientSocket::OnCmdProcess(void *pData, int iDataLen) { HEADER TmpHeader = {0}; char *pTmpData = new char[iDataLen]; memcpy(pTmpData, pData, iDataLen); memcpy(&TmpHeader, pTmpData, sizeof(HEADER)); switch(TmpHeader.FuncCode) { case 0x03://读数据应答 ReadDataRes(pTmpData); break; case 0x10://写数据应答 WriteDataRes(pTmpData); break; case (0x03 + 0x80)://读数据应答异常 ReadDataResError(pTmpData); break; case 0x90://写数据应答异常 WriteDataResError(pTmpData); break; default://错误的功能包 if( pTmpData ) { delete[] pTmpData; pTmpData = NULL; } return -1; } if( pTmpData ) { delete[] pTmpData; pTmpData = NULL; } return 0; } int CClientSocket::ReadDataRes(char *pTmpData) { RESPONSE_STRUCT ResponseStr = {0}; int iHeadLen = sizeof(ResponseStr.Header); memcpy(&ResponseStr.Header, pTmpData, iHeadLen); memcpy(&ResponseStr.DataLen, pTmpData + iHeadLen, sizeof(ResponseStr.DataLen)); if (ResponseStr.DataLen > 0) { memcpy(&ResponseStr.StrRtnMsg, pTmpData + iHeadLen + 1, ResponseStr.DataLen); ResponseStr.nReadResult = 1; m_structResponse = ResponseStr; //TRACE("DataLen1 = %d\r\n", m_structResponse.DataLen); } else { ResponseStr.nReadResult = 0; m_structResponse = ResponseStr; //TRACE("返回数据长度=%d\r\n", ResponseStr.DataLen); return -1; } int nValue; WORD wdValue; memcpy(&wdValue, ResponseStr.StrRtnMsg, sizeof(WORD)); //wdValue = htons(wdValue); nValue = htons(wdValue); //TRACE(">>>>>>>>>结束请求,数据内容=%d\r\n", nValue); #if IS_USE_EVENT SetEvent( m_hSemNet ); #endif return 0; } int CClientSocket::WriteDataRes(char *pTmpData) { memcpy(&m_structWriteResponse, pTmpData, sizeof(WRITESUCCESSRESPONSE)); #if IS_USE_EVENT SetEvent( m_hSemNet ); #endif return 0; } int CClientSocket::ReadDataResError(char *pTmpData) { FAILRESPONSE ResponseStr; memcpy(&ResponseStr, pTmpData, sizeof(FAILRESPONSE)); TRACE("读数据错误\r\n"); return 0; } int CClientSocket::WriteDataResError(char *pTmpData) { return 0; } int CClientSocket::WorkMain(REQUESTPARAM SetBasePara) { if(!m_SocketClient) { TRACE("打开端口错误\r\n"); return ERR_CODE_MODBUS_TCP_NET_FAULT; // 端口通信故障 } int nRet; nRet = RequestStatus(&SetBasePara, sizeof(REQUESTPARAM)); if( nRet != 0 ) { return nRet; // 端口忙 } return nRet; } int CClientSocket::Write(REQUESTWRPARAM writeParam) { if(!m_SocketClient) { TRACE("打开端口错误\r\n"); return ERR_CODE_MODBUS_TCP_NET_FAULT; // 端口通信故障 } int nRet; nRet = RequestStatus(&writeParam, sizeof(REQUESTWRPARAM) - sizeof(writeParam.nWriteResult)); if( nRet != 0 ) { return nRet; // 端口忙 } return nRet; } int CClientSocket::RequestStatus(void *pData, int nLen) { //int iLen = sizeof(REQUESTPARAM); //TRACE("开始请求一个变量数据\r\n"); //TRACE("开始请求寄存器起始地址=%d\r\n", htons(SetBasePara.StartAddr)); #if IS_USE_EVENT if( WaitForSingleObject( m_hSemNet, 0 ) == WAIT_OBJECT_0 ) // 有信号才写串口 { ResetEvent( m_hSemNet ); #endif int nResult = ClientSend((char *)pData, nLen); if( nResult == nLen ) { ; } else { #if IS_USE_EVENT SetEvent( m_hSemNet ); #endif TRACE("发送数据错误\r\n"); return EER_CODE_MODBUS_TCP_NET_WRITE_DATA; } #if IS_USE_EVENT } else { return ERR_CODE_MODBUS_TCP_NET_BUSY; } #endif return 0; } DWORD WINAPI CClientSocket::ReConnectSrvThread( void *pData ) { CClientSocket *pClientSocket = (CClientSocket *)pData; do { if( pClientSocket->m_bSocket == FALSE ) { if ( pClientSocket->m_SocketClient.IsOpen() ) { pClientSocket->DisConnection(); } char chNetPort[8] = {0}; itoa(pClientSocket->m_nNetPort, chNetPort, 10); if( !pClientSocket->Connection(pClientSocket->m_chIpAddr, chNetPort) ) { pClientSocket->m_bSocket = FALSE; } else { pClientSocket->m_bSocket = TRUE; } } }while( WaitForSingleObject( pClientSocket->m_hRunObject, 125L ) == WAIT_TIMEOUT ); return 0; }