使用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