其他分享
首页 > 其他分享> > 使用SOCKET 实现 Modbus TCP 读写

使用SOCKET 实现 Modbus TCP 读写

作者:互联网

将ASCII字符串写入到保持寄存器中,16个寄存器

读16个寄存器,把十六进制的值再转成ASCII

读写一个保持寄存器的值

要实现socket 十六进制发送功能,ASCII和十六进制字符串互转功能

 

此代码共用到Modbus TCP的3个功能码 03 06 10 功能码

03功能码

 

 06功能码

 

10功能码

 

 

 

#include <WS2tcpip.h>
SOCKET m_socket;
sockaddr_in addr;     //定义套接字地址结构变量

代码

  1 BOOL socketTcpConnect(CString strIP, int iPort)
  2 {
  3     WSADATA wsa = { 0 };
  4     WSAStartup(MAKEWORD(2, 2), &wsa);
  5     //初始化socket
  6     m_socket = socket(AF_INET, SOCK_STREAM, 0);
  7     u_long mode = 1;
  8     ioctlsocket(m_socket, FIONBIO, &mode);//设置为非阻塞
  9     if (m_socket == INVALID_SOCKET)
 10     {
 11         AfxMessageBox(_T("初始化 socket error"));
 12         return FALSE;
 13     }
 14     addr.sin_family = AF_INET;
 15     InetPton(AF_INET, strIP, &addr.sin_addr.s_addr);
 16     addr.sin_port = ntohs(iPort);
 17 
 18     //设置connect超时时间
 19     struct timeval timeout;
 20     fd_set r;
 21     int ret;
 22     connect(m_socket, (sockaddr*)&addr, sizeof(addr));
 23     FD_ZERO(&r);
 24     FD_SET(m_socket, &r);
 25 
 26     timeout.tv_sec = 5;
 27     timeout.tv_usec = 0;
 28     ret = select(0, 0, &r, 0, &timeout);
 29 
 30     if (ret <= 0)
 31     {
 32         closesocket(m_socket);
 33         return FALSE;
 34     }
 35     return TRUE;
 36 }
 37 
 38 
 39 
 40 BOOL socketTcpClose()
 41 {
 42     closesocket(m_socket);
 43     return TRUE;
 44 }
 45 
 46 
 47 
 48 void strAsciiTostrHex(char *strAscii, char *strHex, int iAsciiLen)
 49 {
 50     int i = 0;
 51     int j = 0;
 52     for (i = 0, j = 0; i < iAsciiLen; i++, j += 2)
 53     {
 54         sprintf((char*)(strHex + j), "%02X", strAscii[i]);
 55     }
 56 }
 57 
 58 
 59 //一位十六进制转换为十进制
 60 int HexChar(char c)
 61 {
 62     if ((c >= '0') && (c <= '9'))
 63         return c - 0x30;
 64     else if ((c >= 'A') && (c <= 'F'))
 65         return c - 'A' + 10;
 66     else if ((c >= 'a') && (c <= 'f'))
 67         return c - 'a' + 10;
 68     else
 69         return 0x10;
 70 }
 71 
 72 
 73 int strTohex(CString str, char *data)
 74 {
 75     int t, t1;
 76     int rlen = 0;
 77     int len = str.GetLength();
 78     for (int i = 0; i < len; )
 79     {
 80         char l;
 81         char h = str[i];
 82         if (h == ' ')
 83         {
 84             i++;
 85             continue;
 86         }
 87         i++;
 88         if (i >= len)
 89         {
 90             break;
 91         }
 92         l = str[i];
 93         t = HexChar(h);
 94         t1 = HexChar(l);
 95         if ((t == 16) || (t1 == 16))
 96         {
 97             break;
 98         }
 99         else
100         {
101             t = t * 16 + t1;
102         }
103         i++;
104         data[rlen] = (char)t;
105         rlen++;
106     }
107     return rlen;
108 }
109 
110 
111 CString getHexrecv(CHAR *str, int len)
112 {
113     BYTE c_temp;
114     CString str_temp;
115     CString str_res;
116     for (int i = 0; i < len; i++)
117     {
118         c_temp = str[i];
119         str_temp.Format(_T("%02X"), c_temp);
120         str_res = str_res + str_temp;
121     }
122     return str_res;
123 }
124 
125 
126 BOOL socketTcpWrite16Value(int iAddr, CString strHex)
127 {
128     int iZroFillNumber = 0;
129     iZroFillNumber = 64 - strHex.GetLength();
130     CString strZroFill;
131     for (int i = 0; i < iZroFillNumber; i++)
132     {
133         strZroFill += "0";
134     }
135     strHex += strZroFill;
136     CString strAddr, strWrite;
137     strAddr.Format(_T("%04X"), iAddr);
138 
139     strWrite.Format(_T("0000000000270110%s001020%s"), strAddr, strHex);
140     //AfxMessageBox(_T("写命令:") + strWrite);
141     char arraybuf[1024] = { 0 };
142     int len = strTohex(strWrite, arraybuf);
143     send(m_socket, arraybuf, len, 0);//执行转发
144     CString strRecv;
145     memset(arraybuf, 0, 1024);
146     int iCount = 0;
147     while (1)
148     {
149         if (iCount >= 150)
150         {
151             break;
152         }
153         Sleep(20);
154         iCount++;
155         int iRecv = recv(m_socket, arraybuf, 1024, 0);
156         strRecv = getHexrecv(arraybuf, iRecv);
157         if (!strRecv.IsEmpty())
158         {
159             CString strRecvFlag;
160             strRecvFlag.Format(_T("0000000000060110%s0010"), strAddr);
161             if (strRecv == strRecvFlag)
162             {
163                 CString strMsg;
164                 strMsg.Format(_T("写地址%d值%s成功"), iAddr, strHex);
165                 //AfxMessageBox(strMsg);
166                 return TRUE;
167                 break;
168             }
169         }
170     }
171 
172     return FALSE;
173 }
174 
175 
176 
177 int hexcharToInt(char c)
178 {
179     if (c >= '0' && c <= '9') return (c - '0');
180     if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
181     if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
182     return 0;
183 }
184 
185 void strHexTostrAscii(char *strAscii, char *strHex, int iHexLen)
186 {
187     for (int i = 0; i < iHexLen; i += 2)
188     {
189         strAscii[i / 2] = (char)((hexcharToInt(strHex[i]) << 4) | hexcharToInt(strHex[i + 1]));
190     }
191 }
192 
193 
194 //开始位置  长度寄存器个数   一个寄存器保存2个字节
195 BOOL socketTcpReadAsciiValue(int iAddr, int iReadLen)
196 {
197     CString strAddr, strWrite, strReadLen;
198     strAddr.Format(_T("%04X"), iAddr);
199     strReadLen.Format(_T("%04X"), iReadLen);
200 
201     strWrite.Format(_T("0000000000060103%s%s"), strAddr, strReadLen);
202     //AfxMessageBox(_T("读命令:") + strWrite);
203 
204     char arraybuf[1024] = { 0 };
205     int len = strTohex(strWrite, arraybuf);
206     send(m_socket, arraybuf, len, 0);//执行转发
207     CString strRecv;
208     memset(arraybuf, 0, 1024);
209     int iCount = 0;
210     while (1)
211     {
212         if (iCount >= 150)
213         {
214             break;
215         }
216         Sleep(20);
217         iCount++;
218         int iRecv = recv(m_socket, arraybuf, 1024, 0);
219         strRecv = getHexrecv(arraybuf, iRecv);
220         if (!strRecv.IsEmpty())
221         {
222             //AfxMessageBox(strRecv);
223             //获取长度字节数
224             CString strRecvHexLen;
225             strRecvHexLen = strRecv.Mid(16, 2);
226             int iRecvHexLen = _tcstoll(strRecvHexLen, 0, 16);
227             if (iRecvHexLen != (iReadLen * 2))
228             {
229                 AfxMessageBox(_T("返回数据长度不正确"));
230                 return FALSE;
231             }
232             CString strHex;
233             strHex = strRecv.Right(strRecv.GetLength() - 18);
234             //AfxMessageBox(strHex);
235             //前2个是0 后2个是0 4个全是0
236             char cArrAscii[40] = { 0 };
237             char cArrHex[80] = { 0 };
238             sprintf(cArrHex, strHex.GetBuffer(0));
239             //这里会自动忽略后面的0
240             strHexTostrAscii(cArrAscii, cArrHex, strlen(cArrHex));
241 
242             CString strMsg;
243             strMsg.Format(_T("%s"), cArrAscii);
244             //AfxMessageBox(strMsg);
245             sOutParaArray.SetAt(0, cArrAscii);
246             return TRUE;
247             break;
248         }
249     }
250 
251     return FALSE;
252 }
253 
254 //开始位置  长度寄存器个数   一个寄存器保存2个字节
255 BOOL socketTcpReadValue(int iAddr, int iReadLen)
256 {
257     CString strAddr, strWrite, strReadLen;
258     strAddr.Format(_T("%04X"), iAddr);
259     strReadLen.Format(_T("%04X"), iReadLen);
260 
261     strWrite.Format(_T("0000000000060103%s%s"), strAddr, strReadLen);
262     //AfxMessageBox(_T("读命令:") + strWrite);
263 
264     char arraybuf[1024] = { 0 };
265     int len = strTohex(strWrite, arraybuf);
266     send(m_socket, arraybuf, len, 0);//执行转发
267     CString strRecv;
268     memset(arraybuf, 0, 1024);
269     int iCount = 0;
270     while (1)
271     {
272         if (iCount >= 150)
273         {
274             break;
275         }
276         Sleep(20);
277         iCount++;
278         int iRecv = recv(m_socket, arraybuf, 1024, 0);
279         strRecv = getHexrecv(arraybuf, iRecv);
280         if (!strRecv.IsEmpty())
281         {
282             //AfxMessageBox(strRecv);
283             //获取长度字节数
284             CString strRecvHexLen;
285             strRecvHexLen = strRecv.Mid(16, 2);
286             int iRecvHexLen = _tcstoll(strRecvHexLen, 0, 16);
287             if (iRecvHexLen != (iReadLen * 2))
288             {
289                 AfxMessageBox(_T("返回数据长度不正确"));
290                 return FALSE;
291             }
292             CString strHex;
293             strHex = strRecv.Right(strRecv.GetLength() - 18);
294             //AfxMessageBox(strHex);
295             if (iAddr == 98)
296             {
297                 CString strFault;
298                 strFault = AnalysisFault(strHex);
299                 //AfxMessageBox(strFault);
300                 sOutParaArray.SetAt(0, strFault);
301             }
302             else if(iAddr == 106)
303             {
304                 CString strState;
305                 strState = GetChargeState(strHex);
306                 //AfxMessageBox(strState);
307                 sOutParaArray.SetAt(0, strState);
308             }
309 
310             return TRUE;
311             break;
312         }
313     }
314 
315     return FALSE;
316 }
317 
318 
319 
320 BOOL socketTcpWriteValue(int iAddr, int value)
321 {
322     CString strAddr, strWrite, strIndex, strValue;
323     strAddr.Format(_T("%04X"), iAddr);
324     strValue.Format(_T("%04X"), value);
325 
326     strWrite.Format(_T("0000000000060106%s%s"), strAddr, strValue);
327     //AfxMessageBox(_T("写命令:") + strWrite);
328     char arraybuf[1024] = { 0 };
329     int len = strTohex(strWrite, arraybuf);
330     send(m_socket, arraybuf, len, 0);//执行转发
331     CString strRecv;
332     memset(arraybuf, 0, 1024);
333     int iCount = 0;
334     while (1)
335     {
336         if (iCount >= 150)
337         {
338             break;            
339         }
340         Sleep(20);
341         iCount++;
342         int iRecv = recv(m_socket, arraybuf, 1024, 0);
343         strRecv = getHexrecv(arraybuf, iRecv);
344         if (!strRecv.IsEmpty())
345         {
346             if (strWrite == strRecv)
347             {
348                 CString strMsg;
349                 strMsg.Format(_T("写地址%d值%d成功"), iAddr, value);
350                 //AfxMessageBox(strMsg);
351                 return TRUE;
352                 break;
353             }
354         }
355     }
356 
357     return FALSE;
358 }

调用16个寄存器读写

        
//写ASCII字符串到保持寄存器
        BOOL res = socketTcpConnect(strModbusIP, iModbusPort);
        if (!res)
        {
            sprintf(pError, strModbusIP + _T("modbus Socket连接失败"));
            return 0;
        }
        char cArrAscii[40] = { 0 };
        sprintf(cArrAscii, strValue.GetBuffer(0));
        char cArrHex[70] = { 0 };
        strAsciiTostrHex(cArrAscii, cArrHex, strValue.GetLength());
        CString strHex;
        strHex.Format(_T("%s"), cArrHex);

        res = socketTcpWrite16Value(iAddr, strHex);
        if (!res)
        {
            sprintf(pError, "设置充电桩号失败");
            return 0;
        }
        //关闭socket
        socketTcpClose();

//读16个寄存器中的值转换成ASCII字符串
        BOOL res = socketTcpConnect(strModbusIP, iModbusPort);
        if (!res)
        {
            sprintf(pError, strModbusIP + _T("modbus Socket连接失败"));
            return 0;
        }
        res = socketTcpReadAsciiValue(iAddr, 16);
        if (!res)
        {
            sprintf(pError, "读取充电桩号失败");
            return 0;
        }
        //关闭socket
        socketTcpClose();

调用1个寄存器读写

//写一个寄存器的值        
        BOOL res = socketTcpConnect(strModbusIP, iModbusPort);
        if (!res)
        {
            sprintf(pError, strModbusIP + _T("modbus Socket连接失败"));
            return 0;
        }
        res = socketTcpWriteValue(iAddr, 0);
        if (!res)
        {
            sprintf(pError, _T("停止充电失败"));
            return 0;
        }
        //关闭socket
        socketTcpClose();

//读一个寄存器的值
        BOOL res = socketTcpConnect(strModbusIP, iModbusPort);
        if (!res)
        {
            sprintf(pError, strModbusIP + _T("modbus Socket连接失败"));
            return 0;
        }
        res = socketTcpReadValue(iAddr, 1);
        if (!res)
        {
            sprintf(pError, _T("读取充电状态失败"));
            return 0;
        }
        //关闭socket
        socketTcpClose();

 

标签:return,SOCKET,int,res,CString,TCP,Modbus,strRecv,socket
来源: https://www.cnblogs.com/ckrgd/p/16507853.html