|
- #include "TCP_client.h"
-
-
- /*********************************************************************************************
- * 功能 : 检测socket版本
- * 描述 : 检测socket版本是否一致
- * 输入 : 无
- * 输出 : true socket版本一致
- * false socket版本不一致
- *********************************************************************************************/
- bool InitSocket_Version(void)
- {
- WORD sockVersion = MAKEWORD(2, 2);//使用winsocket2.2版本
- WSADATA wsaData;
- if (WSAStartup(sockVersion, &wsaData) != 0)
- {
- return false;
- }
- return true;
- }
-
- /*********************************************************************************************
- * 功能 : IP地址有效性检测
- * 描述 : 检测输入的IP地址是否合法
- * 输入 : IP 输入的IP地址
- * 输出 : true IP地址合法
- * false IP地址非法
- *********************************************************************************************/
- bool Check_IP(string IP)
- {
- int s[4];
- string ip = IP;
- if (ip.length() < 7 || ip.length() > 15) //长度判定
- return false;
- if (sscanf_s(IP.c_str(), "%d.%d.%d.%d", &s[0], &s[1], &s[2], &s[3]) != 4) //IPV4格式正确
- {
- return false;
- }
- string newip = to_string(s[0]) + "." + to_string(s[1]) + "." + to_string(s[2]) + "." + to_string(s[3]);
- if (ip != newip) //前导0
- return false;
- if ((s[0] & 0xffffff00) || (s[1] & 0xffffff00) || (s[2] & 0xffffff00) || (s[3] & 0xffffff00)) //判断每一段大小是否符合要求
- {
- return false;
- }
- return true;
- }
-
- /*********************************************************************************************
- * 功能 : 获取从站IP地址和端口号
- * 描述 : 终端输入从站IP地址和端口号
- * 输入 : IP 地址 (IPV4)
- * *Port_number 端口号(1-65535)
- * 输出 : 无
- *********************************************************************************************/
- void Input_IP(string& IP, unsigned int *Port_number)
- {
- int i = 1;
- do
- {
- if (i == 1)
- {
- cout << "请输入从站IP:";
- i = 0;
- }
- else
- cout << "IP地址格式不正确,请重新输入从站IP:";
- cin >> IP;
- } while (!Check_IP(IP));
-
- i = 1;
- cout << "IP地址输格式入正确,请输入从站端口号:";
- do
- {
- if (i != 1)
- cout << "请重新输入从站端口号:";
- cin >> *Port_number;
- i = 0;
- } while (*Port_number == 0 || *Port_number > 65535); //端口不能为0 ,端口号范围0---65535
-
- }
-
- /*********************************************************************************************
- * 功能 : 初始化客户端
- * 描述 : 根据终端输入从站IP地址和端口号连接对应的服务器,设置超时时间
- * 输入 : IP 地址 (IPV4)
- * Port_number 端口号(1-65535)
- * 输出 : ClientSocket 连接成功的套接字
- *********************************************************************************************/
- SOCKET Init_client(string IP, unsigned int Port_number)
- {
- if (InitSocket_Version() == 0)
- return INVALID_SOCKET;
- SOCKET ClientSocket = socket(AF_INET, SOCK_STREAM, 0);
- sockaddr_in Serversock_in;
- Serversock_in.sin_addr.S_un.S_addr = inet_addr(IP.c_str());
- Serversock_in.sin_family = AF_INET;
- Serversock_in.sin_port = htons(Port_number);
- while (SOCKET_ERROR == connect(ClientSocket, (SOCKADDR*)&Serversock_in, sizeof(SOCKADDR)))
- {
- cout << "尝试连接TCP从站失败" << endl;
- }
- cout << "连接TCP从站成功" << endl;
- TIMEVAL timeout;
- timeout.tv_sec = 20000; //ms
- timeout.tv_usec = 0; //us
- setsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));//设置接收超时时间
- return ClientSocket;
- }
-
- /*********************************************************************************************
- * 功能 : 清除接收缓冲区中的数据
- * 描述 : 每一次发送请求前清空缓存区数据
- * 输入 : ClientSocket 客户端套接字
- * 输出 : 无
- *********************************************************************************************/
- void Clear_recv_buf(SOCKET clientSocket)
- {
- struct timeval tmOut;
- tmOut.tv_sec = 0;
- tmOut.tv_usec = 0;
- fd_set fds;
- int nRet;
- char tmp[2];
- memset(tmp, 0, sizeof(tmp));
- while (1)
- {
- FD_ZERO(&fds);
- FD_SET(clientSocket, &fds);
- nRet = select(FD_SETSIZE, &fds, NULL, NULL, &tmOut);
- if (nRet == 0)
- break;
- recv(clientSocket, tmp, 1, 0);
- }
- }
-
- void Printf_Coil_date(UINT8 *Response_Message, UINT8 *Request_Message)
- {
- printf("从站设备ID %02X 功能码为 %02X\n", Response_Message[6], Response_Message[7]);
- unsigned int temp1 = ((Request_Message[8] << 8) | Request_Message[9])+1;
- unsigned int Number = ((Request_Message[10] << 8) | Request_Message[11]);
- printf("线圈起始地址为%d \n",temp1);
- unsigned int temp = temp1;
- for (int i = 0; i < Response_Message[8]; i++)
- {
- unsigned int temp2 = temp + 7;
- if (temp2 > temp1 + Number - 1)
- temp2 = temp1 + Number - 1;
- printf("线圈第%d --- %d的状态为:%02X \n", temp2, temp, Response_Message[9+i]);
- temp = temp + 8;
- }
- }
-
- void Printf_Register_date(UINT8 *Response_Message, UINT8 *Request_Message)
- {
- printf("从站设备ID %02X 功能码为 %02X\n", Response_Message[6], Response_Message[7]);
- unsigned int temp1 = ((Request_Message[8] << 8) | Request_Message[9]) + 1;
- unsigned int Number = ((Request_Message[10] << 8) | Request_Message[11]);
- printf("寄存器起始地址为%d \n", temp1);
- for (int i = 0; i < Response_Message[8]; i = i + 2)
- {
- printf("寄存器第%d的值为:%02X %02X \n", temp1++, Response_Message[9 + i], Response_Message[10+i]);
- }
-
- }
- void Printf_Anomaly_date(UINT8 *Response_Message)
- {
- UINT8 a = Response_Message[8];
- printf("从站设备ID %02X 功能码为 %02X\n", Response_Message[6], Response_Message[7]);
- switch (a)
- {
- case 0x01: printf("%02X : 从站设备不支持此功能码",a); break;
- case 0x02: printf("%02X : 指定的数据地址在从站设备中不存在",a); break;
- case 0x03: printf("%02X : 指定的数据超过范围或者不允许使用",a); break;
- case 0x04: printf("%02X : 从站设备处理响应的过程中,出现未知错误等",a); break;
- default: printf("Unkown Other Error!!!!!");
- }
- }
-
-
-
-
- bool Analysis_Response_Message(UINT8 *Response_Message, UINT8 *Request_Message, int Response_Message_len)
- {
- if (Response_Message[7] == Request_Message[7] + 0x80 && Response_Message_len == 9)//先处理异常响应
- {
- Printf_Anomaly_date(Response_Message);
- return true;
- }
- else if (Response_Message[6] == Request_Message[6]) //判断是否是正常响应帧
- {
- if (Response_Message[7] == 0x01 && Response_Message_len - 6 == Response_Message[5])
- Printf_Coil_date(Response_Message, Request_Message);
- if (Response_Message[7] == 0x03 && Response_Message_len - 6 == Response_Message[5])
- Printf_Register_date(Response_Message, Request_Message);
- if (Response_Message[7] == 0x0F)
- printf("成功写入从站线圈%d个\n", ((Request_Message[10] << 8) | Request_Message[11]));
- if (Response_Message[7] == 0x10)
- printf("成功写入从站寄存器%d个\n" ,((Request_Message[10] << 8) | Request_Message[11]));
- return true;
- }
- return false;
- }
-
- /*********************************************************************************************
- * 功能 : 运行客户端
- * 描述 : 根据终端输入从站IP地址和端口号连接对应的服务器并且生成发送请求等待响应
- * 输入 : IP 地址 (IPV4)
- * Port_number 端口号(1-65535)
- * 输出 : false 执行出错 true 执行成功
- *********************************************************************************************/
- bool Tcp_client(string IP, unsigned int Port_number)
- {
- SOCKET ClientSocket = Init_client(IP, Port_number);
- if (INVALID_SOCKET == ClientSocket)
- {
- cout << "初始化主站失败" << endl;
- return false;
- }
- UINT8 Request_Message[260];
- UINT8 Response_Message[260];
- while (true)
- {
-
- int Function_code = Input_Function_code();
- unsigned int Operations_Number = Input_Operations_Number(Function_code);
- unsigned int Starting_address = Input_Starting_address();
- string Write_date = Input_Write_date(Function_code, Operations_Number);
- int Request_Message_len = Crate_TCP_Message(Request_Message, Function_code, Operations_Number, Starting_address, Write_date);
- printf("主站请求 :");
- for (int i = 0; i < Request_Message_len; i++)
- {
- printf("%02x ", Request_Message[i]);
- }
- printf("\n");
- Log_Note(Request_Message, 1, Request_Message_len);
- Clear_recv_buf(ClientSocket);
- send(ClientSocket, (char*)Request_Message, Request_Message_len, 0);
- memset(Response_Message, 0, 260);
- int Response_Message_len = recv(ClientSocket, (char*)Response_Message, 260, 0);
- if (Response_Message_len > 0)
- {
- Log_Note(Response_Message, 0, Response_Message_len);
- printf("从站响应 :");
- for (int i = 0; i < Response_Message_len; i++)
- {
- printf("0x%02x, ", Response_Message[i]);
- }
- printf("\n");
- if (Analysis_Response_Message(Response_Message, Request_Message, Response_Message_len))
- printf("响应报文异常\n\n");
- }
- else
- cout << "响应超时" << endl;
- }
- //关闭套接字
- closesocket(ClientSocket);
- //关闭服务
- WSACleanup();
- return true;
- }
|