// ClientSocketThread.cpp : implementation file // #include "stdafx.h" #include "ModbusClient.h" // CModbusClient const UINT glServerPort = 502; #define RECVDATA_BUFLEN 1024000 //数据接收缓冲区长度 #define DATALEN_PERTIME 512 //单次从Scoket接收的数据长度 #define DATADEAL_BUFLEN 512 //数据处理缓冲区长度(TCP帧最大数据长度) #define SOCKET_TIME_OUT 500 IMPLEMENT_DYNCREATE(CModbusClient, CWinThread) CModbusClient::CModbusClient(CString strIp, int nPort, HWND hWnd) { m_pRecvDataBuffer = NULL; m_pDealBuf = NULL; m_iWritePos = 0; m_iReadPos = 0; m_llDataTotalLen = 0; m_llReadTotal = 0; m_strSerIP = strIp; m_hWnd = hWnd; m_bConnected = FALSE; m_ReadEventHandle = CreateEvent(NULL, TRUE, FALSE, NULL); //必须手动复位 m_WriteEventHandle = CreateEvent(NULL, TRUE, FALSE, NULL); //必须手动复位 } CModbusClient::CModbusClient() { } CModbusClient::~CModbusClient() { if (m_pDealBuf) { delete m_pDealBuf; m_pDealBuf =NULL; } if (m_pRecvDataBuffer) { delete m_pRecvDataBuffer; m_pRecvDataBuffer =NULL; } } BOOL CModbusClient::InitInstance() { if (!AfxSocketInit()) // 初始化CSocket必须调用的 { CWinThread::InitInstance(); //立刻退出 return FALSE; } //创建socket if (!m_socket.Create()) { //创建socket失败 CWinThread::InitInstance(); //立刻退出 return FALSE; } // 设置发送超时时间,单位毫秒 int nTimeout = SOCKET_TIME_OUT; m_socket.SetSockOpt(SO_SNDTIMEO, (char*)&nTimeout, sizeof(nTimeout), SOL_SOCKET); // 设置接收超时时间,单位毫秒 nTimeout = SOCKET_TIME_OUT; m_socket.SetSockOpt(SO_RCVTIMEO, (char*)&nTimeout, sizeof(nTimeout), SOL_SOCKET); //m_socket.m_pMainDlg = m_pMainDlg; m_socket.m_pThrd = this; if (!m_socket.Connect(m_strSerIP, glServerPort)) { CWinThread::InitInstance(); //立刻退出 m_bConnected = FALSE; //return FALSE; } else { m_bConnected = TRUE; //连接成功后,通知主界面 PostMessage(m_hWnd, WM_NETMESSAGE, NET_CONNECT_OK, (LPARAM)m_bDevID); } m_pRecvDataBuffer = new BYTE[RECVDATA_BUFLEN]; ASSERT(m_pRecvDataBuffer != NULL); m_pDealBuf = new BYTE[DATADEAL_BUFLEN]; ASSERT(m_pDealBuf != NULL); m_iWritePos =0; m_iReadPos =0; m_llDataTotalLen =0; m_llReadTotal =0; m_wTcpID =0; return TRUE; //线程不会立刻退出 } int CModbusClient::ExitInstance() { if (m_socket.m_hSocket != INVALID_SOCKET) { m_socket.ShutDown(2); m_socket.Close(); } //m_bConnected = FALSE; return CWinThread::ExitInstance(); } BEGIN_MESSAGE_MAP(CModbusClient, CWinThread) ON_THREAD_MESSAGE(WM_THREAD_RECV, OnCustomMsg) END_MESSAGE_MAP() // CModbusClient message handlers void CModbusClient::OnCustomMsg(WPARAM wParam,LPARAM lParam) { BYTE pReadBf[DATALEN_PERTIME+1] = {0}; int iRdLen =0; switch(wParam) { case WP_WPARA_RECV: // 接收数据,先把接收数据事件关掉 m_socket.AsyncSelect(FD_CLOSE); //读取数据 iRdLen = m_socket.Receive(pReadBf,DATALEN_PERTIME); if (0 ==iRdLen) { //ToDo:对端断开链接 PostMessage(m_hWnd, WM_NETMESSAGE, NET_DISCONNECT, (LPARAM)m_bDevID); OutputDebugString(_T("CSerSocketThread:1-读数据长度为0,TCP链接断开......")); return; } //缓冲区尾部不能容纳读取的数据,要分开放入缓冲区尾部、头部 if(m_iWritePos + iRdLen > RECVDATA_BUFLEN) { int iTailLen = RECVDATA_BUFLEN - m_iWritePos; memcpy(m_pRecvDataBuffer +m_iWritePos,pReadBf,iTailLen); int iHeadLen = iRdLen - iTailLen; memcpy(m_pRecvDataBuffer,pReadBf + iTailLen,iHeadLen); m_iWritePos = iHeadLen; }else{ //缓冲区尾部足够容纳本次数据 memcpy(m_pRecvDataBuffer+m_iWritePos,pReadBf,iRdLen); m_iWritePos += iRdLen; } //接收数据总长度 m_llDataTotalLen += iRdLen; AnalysisRecvData(); //重新打开接收数据事件 m_socket.AsyncSelect(FD_READ|FD_CLOSE); break; case WP_WPARA_CLOSE: PostMessage(m_hWnd, WM_NETMESSAGE, NET_DISCONNECT, (LPARAM)m_bDevID); //m_socket.Close(); OutputDebugString(_T("TCP链接断开......")); break; case WP_WPARA_THREAD_QUIT: PostQuitMessage(0); break; } } void CModbusClient::AnalysisRecvData() { if (m_llReadTotal + sizeof(ST_MODBUS_MBAP_HEADER) < m_llDataTotalLen) //缓冲区中未读数据长度大于MBAP长 { memset(m_pDealBuf,0,DATADEAL_BUFLEN); //写指针随时变动,记录当前位置 int iRdCurrPos = m_iReadPos; int iWrtCurrPos = m_iWritePos; ST_MODBUS_MBAP_HEADER stMbap; if(iRdCurrPos < iWrtCurrPos) //写指针超前读指针,数据在两个指针之间 { memcpy(&stMbap,m_pRecvDataBuffer+iRdCurrPos,sizeof(ST_MODBUS_MBAP_HEADER)); if (m_llReadTotal + sizeof(ST_MODBUS_MBAP_HEADER) +(ntohs(stMbap.wLen) -1) <= m_llDataTotalLen) { memcpy(m_pDealBuf,m_pRecvDataBuffer+iRdCurrPos,sizeof(ST_MODBUS_MBAP_HEADER)+ ntohs(stMbap.wLen) -1); DealFrameData(m_pDealBuf); m_iReadPos +=(sizeof(ST_MODBUS_MBAP_HEADER) + ntohs(stMbap.wLen) -1); m_llReadTotal += (sizeof(ST_MODBUS_MBAP_HEADER) + ntohs(stMbap.wLen) -1); }else{ return; //不够一帧 } } else{//写指针滞后读指针,数据在首尾两头 if (iRdCurrPos +sizeof(ST_MODBUS_MBAP_HEADER) <= RECVDATA_BUFLEN) { memcpy(&stMbap,m_pRecvDataBuffer+iRdCurrPos,sizeof(ST_MODBUS_MBAP_HEADER)); if (m_llReadTotal+sizeof(ST_MODBUS_MBAP_HEADER)+ ntohs(stMbap.wLen) -1 <= m_llDataTotalLen) { if (iRdCurrPos + sizeof(ST_MODBUS_MBAP_HEADER) + ntohs(stMbap.wLen) -1 <= RECVDATA_BUFLEN) //写指针滞后读指针,读指针到缓冲区尾仍够一帧数据 { memcpy(m_pDealBuf,m_pRecvDataBuffer+iRdCurrPos,sizeof(ST_MODBUS_MBAP_HEADER)+ ntohs(stMbap.wLen) -1); DealFrameData(m_pDealBuf); m_iReadPos +=(sizeof(ST_MODBUS_MBAP_HEADER) + ntohs(stMbap.wLen) -1); m_llReadTotal += (sizeof(ST_MODBUS_MBAP_HEADER) +ntohs(stMbap.wLen) -1); m_iReadPos =m_iReadPos % RECVDATA_BUFLEN; }else{ //当前读指针到缓冲区尾,够MBAP头长,但数据不够 memcpy(m_pDealBuf,m_pRecvDataBuffer+iRdCurrPos,RECVDATA_BUFLEN - iRdCurrPos); memcpy(m_pDealBuf+RECVDATA_BUFLEN - iRdCurrPos,m_pRecvDataBuffer,sizeof(ST_MODBUS_MBAP_HEADER) + ntohs(stMbap.wLen) -1 -(RECVDATA_BUFLEN - iRdCurrPos)); DealFrameData(m_pDealBuf); m_iReadPos = sizeof(ST_MODBUS_MBAP_HEADER) +ntohs(stMbap.wLen) -1 -(RECVDATA_BUFLEN - iRdCurrPos); m_llReadTotal += (sizeof(ST_MODBUS_MBAP_HEADER) + ntohs(stMbap.wLen) -1); } } else{ return;//不够一帧 } }else{ //当前读指针到缓冲区尾不够MBAP头,大部分数据在缓冲区头 memcpy(m_pDealBuf,m_pRecvDataBuffer+iRdCurrPos,RECVDATA_BUFLEN -iRdCurrPos); memcpy(m_pDealBuf+RECVDATA_BUFLEN -iRdCurrPos,m_pRecvDataBuffer,sizeof(ST_MODBUS_MBAP_HEADER) -(RECVDATA_BUFLEN - iRdCurrPos)); memcpy(&stMbap,m_pDealBuf,sizeof(ST_MODBUS_MBAP_HEADER)); if (m_llReadTotal+sizeof(ST_MODBUS_MBAP_HEADER)+ ntohs(stMbap.wLen) -1 <= m_llDataTotalLen) { memcpy(m_pDealBuf,m_pRecvDataBuffer+iRdCurrPos,RECVDATA_BUFLEN -iRdCurrPos); memcpy(m_pDealBuf+RECVDATA_BUFLEN -iRdCurrPos,m_pRecvDataBuffer,sizeof(ST_MODBUS_MBAP_HEADER) -(RECVDATA_BUFLEN - iRdCurrPos) + ntohs(stMbap.wLen) -1); DealFrameData(m_pDealBuf); m_iReadPos = sizeof(ST_MODBUS_MBAP_HEADER) -(RECVDATA_BUFLEN - iRdCurrPos) + ntohs(stMbap.wLen) -1; m_llReadTotal += (sizeof(ST_MODBUS_MBAP_HEADER) + ntohs(stMbap.wLen) -1); } else{ return;//不够一帧 } } } } } void CModbusClient::DealFrameData(BYTE* pData) { BYTE bSampleData[512] ={0}; NET_PACKET* pNetPacket = NULL; int nLen = 0; ST_MODBUS_MBAP_HEADER stMbap; BYTE bFuncCode = pData[sizeof(ST_MODBUS_MBAP_HEADER)]; memcpy(&stMbap,pData,sizeof(ST_MODBUS_MBAP_HEADER)); int iFrmLen = ntohs(stMbap.wLen) +6; memcpy(bSampleData,pData,iFrmLen); memset(&m_stReadRspFrm, 0, sizeof(ST_MODBUS_SERVER_RSPREAD_FRAME)); memset(&m_stWrtRspFrm, 0, sizeof(ST_MODBUS_SERVER_RSPWRT_FRAME)); memset(&m_stRspErrFrm, 0, sizeof(ST_MODBUS_SERVER_RSPERR_FRAME)); int iDataLen =ntohs(stMbap.wLen) -1; switch(bFuncCode) { case EN_MODBUS_READ_SINGLECOIL: case EN_MODBUS_READ_PERSISREG: memcpy(&m_stReadRspFrm,pData,iFrmLen); //ST_MODBUS_SERVER_RSPREAD_FRAME的成员bRtnData定义了255字节,实际占用不到255,不能用sizeof作为拷贝长度 SetEvent(m_ReadEventHandle); //((CMechanicalArmOptDlg*)m_pMainDlg)->OnDevReadRspDataToBuffer(m_bDevID,stReadRspFrm); /*pNetPacket = new NET_PACKET; pNetPacket->enType = NET_RD_MSG_RET; pNetPacket->nDevId = m_bDevID; pNetPacket->pData = new char[iFrmLen + 1]; memcpy(pNetPacket->pData, pData, iFrmLen); pNetPacket->pData[iFrmLen] = '\0'; pNetPacket->lLen = iFrmLen; PostMessage(m_hWnd, WM_NETMESSAGE, NET_DATA_MSG, (LPARAM)pNetPacket);*/ //delete[] pNetPacket->pData; //delete pNetPacket; break; case EN_MODBUS_WRITE_SINGLECOIL: case EN_MODBUS_WRITE_MULTIREG: memcpy(&m_stWrtRspFrm,pData,sizeof(ST_MODBUS_SERVER_RSPWRT_FRAME)); SetEvent(m_WriteEventHandle); //((CMechanicalArmOptDlg*)m_pMainDlg)->OnDevWrtRspDataToBuffer(m_bDevID,stWrtRspFrm); /*nLen = sizeof(ST_MODBUS_SERVER_RSPWRT_FRAME); pNetPacket = new NET_PACKET; pNetPacket->enType = NET_WR_MSG_RET; pNetPacket->nDevId = m_bDevID; pNetPacket->pData = new char[nLen + 1]; memcpy(pNetPacket->pData, pData, nLen); pNetPacket->pData[nLen] = '\0'; pNetPacket->lLen = nLen; PostMessage(m_hWnd, WM_NETMESSAGE, NET_DATA_MSG, (LPARAM)pNetPacket);*/ break; //ToDo:错误处理 case EN_MODBUS_READ_SINGLECOIL_RSPERR: case EN_MODBUS_READ_PERSISREG_RSPERR: case EN_MODBUS_WRITE_SINGLECOIL_RSPERR: case EN_MODBUS_WRITE_MULTIREG_RSPERR: memcpy(&m_stWrtRspFrm,pData,sizeof(ST_MODBUS_SERVER_RSPERR_FRAME)); break; } } int CModbusClient::WriteMultipleRegisters(int nRegAddr, int nRegCnt, short * pWriteData) { if (m_bConnected == FALSE) { PostMessage(m_hWnd, WM_NETMESSAGE, NET_DISCONNECT, (LPARAM)m_bDevID); return -1; } BYTE bData[512] = { 0 }; if (m_wTcpID + 1 == 0xFFFF) { m_wTcpID = 1; } else { m_wTcpID++; } //发送写多个寄存器报文 ST_MODBUS_CLIENT_RQTWRTMULTIREG_FRAME frame; ST_MODBUS_MBAP_HEADER stMbapHeader; stMbapHeader.wTransFlag = htons(m_wTcpID); stMbapHeader.wProtocolFlag = 0; stMbapHeader.wLen = htons(7 + nRegCnt*2); stMbapHeader.bUnitFlag = 0x01; frame.stMbapHeader = stMbapHeader; frame.bFuncConde = 0x10; //功能码 frame.wStartAddr = htons(nRegAddr - 40001); //寄存器地址 frame.wRegNum = htons(nRegCnt); //寄存器的个数 frame.bLen = nRegCnt * 2; //数据字节长度(寄存器个数*2) for (int i = 0; i < nRegCnt; i++) { UINT16 uintValue = htons(*(pWriteData+i)); char* byteArray = (char*)(&uintValue); // 创建一个4字节的字节数组 for (int j = 0; j < 2; ++j) { frame.bRegVal[i*2 + j] = byteArray[j]; } } int iRtnsend = m_socket.Send(&frame, sizeof(ST_MODBUS_CLIENT_RQTWRTMULTIREG_FRAME) - (255 - nRegCnt * 2)); if (iRtnsend > 0) { //等待读返回的信号量 switch (::WaitForSingleObject(m_WriteEventHandle, SOCKET_TIME_OUT)) { case WAIT_OBJECT_0: { ::ResetEvent(m_WriteEventHandle); break; } case WAIT_TIMEOUT: case WAIT_FAILED: default: { PostMessage(m_hWnd, WM_NETMESSAGE, NET_DISCONNECT, (LPARAM)m_bDevID); break; } } } return iRtnsend; } int CModbusClient::ReadMultipleRegisters(int nRegAddr, int nRegCnt, short * pReadData) { if (m_bConnected == FALSE) { PostMessage(m_hWnd, WM_NETMESSAGE, NET_DISCONNECT, (LPARAM)m_bDevID); return -1; } BYTE bData[512] = { 0 }; if (m_wTcpID + 1 == 0xFFFF) { m_wTcpID = 1; } else { m_wTcpID++; } //发送读多个寄存器报文 ST_MODBUS_CLIENT_RQTREAD_FRAME frame; ST_MODBUS_MBAP_HEADER stMbapHeader; stMbapHeader.wTransFlag = htons(m_wTcpID); stMbapHeader.wProtocolFlag = 0; stMbapHeader.wLen = htons(6); stMbapHeader.bUnitFlag = 0x01; frame.stMbapHeader = stMbapHeader; frame.bFuncConde = 0x03; //功能码 frame.wStartAddr = htons(nRegAddr - 40001); //寄存器地址 frame.wRegNum = htons(nRegCnt); //寄存器的个数 int iRtnsend = m_socket.Send(&frame, sizeof(ST_MODBUS_CLIENT_RQTREAD_FRAME)); if (iRtnsend > 0) { //等待读返回的信号量 switch (::WaitForSingleObject(m_ReadEventHandle, SOCKET_TIME_OUT)) { case WAIT_OBJECT_0: { short *pData = (short *)(m_stReadRspFrm.bRtnData); for (int i = 0; i < m_stReadRspFrm.bLen / 2; i++) { pReadData[i] = htons(*(pData + i)); } ::ResetEvent(m_ReadEventHandle); break; } case WAIT_TIMEOUT: case WAIT_FAILED: default: { PostMessage(m_hWnd, WM_NETMESSAGE, NET_DISCONNECT, (LPARAM)m_bDevID); break; } } } return iRtnsend; }