You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

262 lines
9.1 KiB

  1. #include "TCP_client.h"
  2. /*********************************************************************************************
  3. * 功能    : 检测socket版本
  4. * 描述   : 检测socket版本是否一致
  5. * 输入 : 无
  6. * 输出 : true socket版本一致
  7. * false socket版本不一致
  8. *********************************************************************************************/
  9. bool InitSocket_Version(void)
  10. {
  11. WORD sockVersion = MAKEWORD(2, 2);//使用winsocket2.2版本
  12. WSADATA wsaData;
  13. if (WSAStartup(sockVersion, &wsaData) != 0)
  14. {
  15. return false;
  16. }
  17. return true;
  18. }
  19. /*********************************************************************************************
  20. * 功能    : IP地址有效性检测
  21. * 描述   : 检测输入的IP地址是否合法
  22. * 输入 : IP 输入的IP地址
  23. * 输出 : true IP地址合法
  24. * false IP地址非法
  25. *********************************************************************************************/
  26. bool Check_IP(string IP)
  27. {
  28. int s[4];
  29. string ip = IP;
  30. if (ip.length() < 7 || ip.length() > 15) //长度判定
  31. return false;
  32. if (sscanf_s(IP.c_str(), "%d.%d.%d.%d", &s[0], &s[1], &s[2], &s[3]) != 4) //IPV4格式正确
  33. {
  34. return false;
  35. }
  36. string newip = to_string(s[0]) + "." + to_string(s[1]) + "." + to_string(s[2]) + "." + to_string(s[3]);
  37. if (ip != newip) //前导0
  38. return false;
  39. if ((s[0] & 0xffffff00) || (s[1] & 0xffffff00) || (s[2] & 0xffffff00) || (s[3] & 0xffffff00)) //判断每一段大小是否符合要求
  40. {
  41. return false;
  42. }
  43. return true;
  44. }
  45. /*********************************************************************************************
  46. * 功能    : 获取从站IP地址和端口号
  47. * 描述   : 终端输入从站IP地址和端口号
  48. * 输入 : IP 地址 (IPV4)
  49. * *Port_number 端口号(1-65535)
  50. * 输出 : 无
  51. *********************************************************************************************/
  52. void Input_IP(string& IP, unsigned int *Port_number)
  53. {
  54. int i = 1;
  55. do
  56. {
  57. if (i == 1)
  58. {
  59. cout << "请输入从站IP:";
  60. i = 0;
  61. }
  62. else
  63. cout << "IP地址格式不正确,请重新输入从站IP:";
  64. cin >> IP;
  65. } while (!Check_IP(IP));
  66. i = 1;
  67. cout << "IP地址输格式入正确,请输入从站端口号:";
  68. do
  69. {
  70. if (i != 1)
  71. cout << "请重新输入从站端口号:";
  72. cin >> *Port_number;
  73. i = 0;
  74. } while (*Port_number == 0 || *Port_number > 65535); //端口不能为0 ,端口号范围0---65535
  75. }
  76. /*********************************************************************************************
  77. * 功能    : 初始化客户端
  78. * 描述   : 根据终端输入从站IP地址和端口号连接对应的服务器,设置超时时间
  79. * 输入 : IP 地址 (IPV4)
  80. * Port_number 端口号(1-65535)
  81. * 输出 : ClientSocket 连接成功的套接字
  82. *********************************************************************************************/
  83. SOCKET Init_client(string IP, unsigned int Port_number)
  84. {
  85. if (InitSocket_Version() == 0)
  86. return INVALID_SOCKET;
  87. SOCKET ClientSocket = socket(AF_INET, SOCK_STREAM, 0);
  88. sockaddr_in Serversock_in;
  89. Serversock_in.sin_addr.S_un.S_addr = inet_addr(IP.c_str());
  90. Serversock_in.sin_family = AF_INET;
  91. Serversock_in.sin_port = htons(Port_number);
  92. while (SOCKET_ERROR == connect(ClientSocket, (SOCKADDR*)&Serversock_in, sizeof(SOCKADDR)))
  93. {
  94. cout << "尝试连接TCP从站失败" << endl;
  95. }
  96. cout << "连接TCP从站成功" << endl;
  97. TIMEVAL timeout;
  98. timeout.tv_sec = 20000; //ms
  99. timeout.tv_usec = 0; //us
  100. setsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));//设置接收超时时间
  101. return ClientSocket;
  102. }
  103. /*********************************************************************************************
  104. * 功能    : 清除接收缓冲区中的数据
  105. * 描述   : 每一次发送请求前清空缓存区数据
  106. * 输入 : ClientSocket 客户端套接字
  107. * 输出 : 无
  108. *********************************************************************************************/
  109. void Clear_recv_buf(SOCKET clientSocket)
  110. {
  111. struct timeval tmOut;
  112. tmOut.tv_sec = 0;
  113. tmOut.tv_usec = 0;
  114. fd_set fds;
  115. int nRet;
  116. char tmp[2];
  117. memset(tmp, 0, sizeof(tmp));
  118. while (1)
  119. {
  120. FD_ZERO(&fds);
  121. FD_SET(clientSocket, &fds);
  122. nRet = select(FD_SETSIZE, &fds, NULL, NULL, &tmOut);
  123. if (nRet == 0)
  124. break;
  125. recv(clientSocket, tmp, 1, 0);
  126. }
  127. }
  128. void Printf_Coil_date(UINT8 *Response_Message, UINT8 *Request_Message)
  129. {
  130. printf("从站设备ID %02X 功能码为 %02X\n", Response_Message[6], Response_Message[7]);
  131. unsigned int temp1 = ((Request_Message[8] << 8) | Request_Message[9])+1;
  132. unsigned int Number = ((Request_Message[10] << 8) | Request_Message[11]);
  133. printf("线圈起始地址为%d \n",temp1);
  134. unsigned int temp = temp1;
  135. for (int i = 0; i < Response_Message[8]; i++)
  136. {
  137. unsigned int temp2 = temp + 7;
  138. if (temp2 > temp1 + Number - 1)
  139. temp2 = temp1 + Number - 1;
  140. printf("线圈第%d --- %d的状态为:%02X \n", temp2, temp, Response_Message[9+i]);
  141. temp = temp + 8;
  142. }
  143. }
  144. void Printf_Register_date(UINT8 *Response_Message, UINT8 *Request_Message)
  145. {
  146. printf("从站设备ID %02X 功能码为 %02X\n", Response_Message[6], Response_Message[7]);
  147. unsigned int temp1 = ((Request_Message[8] << 8) | Request_Message[9]) + 1;
  148. unsigned int Number = ((Request_Message[10] << 8) | Request_Message[11]);
  149. printf("寄存器起始地址为%d \n", temp1);
  150. for (int i = 0; i < Response_Message[8]; i = i + 2)
  151. {
  152. printf("寄存器第%d的值为:%02X %02X \n", temp1++, Response_Message[9 + i], Response_Message[10+i]);
  153. }
  154. }
  155. void Printf_Anomaly_date(UINT8 *Response_Message)
  156. {
  157. UINT8 a = Response_Message[8];
  158. printf("从站设备ID %02X 功能码为 %02X\n", Response_Message[6], Response_Message[7]);
  159. switch (a)
  160. {
  161. case 0x01: printf("%02X : 从站设备不支持此功能码",a); break;
  162. case 0x02: printf("%02X : 指定的数据地址在从站设备中不存在",a); break;
  163. case 0x03: printf("%02X : 指定的数据超过范围或者不允许使用",a); break;
  164. case 0x04: printf("%02X : 从站设备处理响应的过程中,出现未知错误等",a); break;
  165. default: printf("Unkown Other Error!!!!!");
  166. }
  167. }
  168. bool Analysis_Response_Message(UINT8 *Response_Message, UINT8 *Request_Message, int Response_Message_len)
  169. {
  170. if (Response_Message[7] == Request_Message[7] + 0x80 && Response_Message_len == 9)//先处理异常响应
  171. {
  172. Printf_Anomaly_date(Response_Message);
  173. return true;
  174. }
  175. else if (Response_Message[6] == Request_Message[6]) //判断是否是正常响应帧
  176. {
  177. if (Response_Message[7] == 0x01 && Response_Message_len - 6 == Response_Message[5])
  178. Printf_Coil_date(Response_Message, Request_Message);
  179. if (Response_Message[7] == 0x03 && Response_Message_len - 6 == Response_Message[5])
  180. Printf_Register_date(Response_Message, Request_Message);
  181. if (Response_Message[7] == 0x0F)
  182. printf("成功写入从站线圈%d个\n", ((Request_Message[10] << 8) | Request_Message[11]));
  183. if (Response_Message[7] == 0x10)
  184. printf("成功写入从站寄存器%d个\n" ,((Request_Message[10] << 8) | Request_Message[11]));
  185. return true;
  186. }
  187. return false;
  188. }
  189. /*********************************************************************************************
  190. * 功能    : 运行客户端
  191. * 描述   : 根据终端输入从站IP地址和端口号连接对应的服务器并且生成发送请求等待响应
  192. * 输入 : IP 地址 (IPV4)
  193. * Port_number 端口号(1-65535)
  194. * 输出 : false 执行出错 true 执行成功
  195. *********************************************************************************************/
  196. bool Tcp_client(string IP, unsigned int Port_number)
  197. {
  198. SOCKET ClientSocket = Init_client(IP, Port_number);
  199. if (INVALID_SOCKET == ClientSocket)
  200. {
  201. cout << "初始化主站失败" << endl;
  202. return false;
  203. }
  204. UINT8 Request_Message[260];
  205. UINT8 Response_Message[260];
  206. while (true)
  207. {
  208. int Function_code = Input_Function_code();
  209. unsigned int Operations_Number = Input_Operations_Number(Function_code);
  210. unsigned int Starting_address = Input_Starting_address();
  211. string Write_date = Input_Write_date(Function_code, Operations_Number);
  212. int Request_Message_len = Crate_TCP_Message(Request_Message, Function_code, Operations_Number, Starting_address, Write_date);
  213. printf("主站请求 :");
  214. for (int i = 0; i < Request_Message_len; i++)
  215. {
  216. printf("%02x ", Request_Message[i]);
  217. }
  218. printf("\n");
  219. Log_Note(Request_Message, 1, Request_Message_len);
  220. Clear_recv_buf(ClientSocket);
  221. send(ClientSocket, (char*)Request_Message, Request_Message_len, 0);
  222. memset(Response_Message, 0, 260);
  223. int Response_Message_len = recv(ClientSocket, (char*)Response_Message, 260, 0);
  224. if (Response_Message_len > 0)
  225. {
  226. Log_Note(Response_Message, 0, Response_Message_len);
  227. printf("从站响应 :");
  228. for (int i = 0; i < Response_Message_len; i++)
  229. {
  230. printf("0x%02x, ", Response_Message[i]);
  231. }
  232. printf("\n");
  233. if (Analysis_Response_Message(Response_Message, Request_Message, Response_Message_len))
  234. printf("响应报文异常\n\n");
  235. }
  236. else
  237. cout << "响应超时" << endl;
  238. }
  239. //关闭套接字
  240. closesocket(ClientSocket);
  241. //关闭服务
  242. WSACleanup();
  243. return true;
  244. }