diff --git a/Modbus_communication/Modbus_TCP/TCP_client.cpp b/Modbus_communication/Modbus_TCP/TCP_client.cpp index 2c11a15..d518220 100644 --- a/Modbus_communication/Modbus_TCP/TCP_client.cpp +++ b/Modbus_communication/Modbus_TCP/TCP_client.cpp @@ -1,5 +1,92 @@ -#include "TCP_client.h" +#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) @@ -11,31 +98,124 @@ SOCKET Init_client(string IP, unsigned int Port_number) Serversock_in.sin_port = htons(Port_number); while (SOCKET_ERROR == connect(ClientSocket, (SOCKADDR*)&Serversock_in, sizeof(SOCKADDR))) { - cout << "TCPվʧ" << endl; + cout << "尝试连接TCP从站失败" << endl; } - cout << "TCPվɹ" << endl; + cout << "连接TCP从站成功" << endl; + TIMEVAL timeout; + timeout.tv_sec = 2000; //ms + timeout.tv_usec = 0; //us + setsockopt(ClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));//设置接收超时时间 return ClientSocket; } -int Tcp_client(string IP, unsigned int Port_number) +/********************************************************************************************* +* 功能    : 清除接收缓冲区中的数据 +* 描述   : 每一次发送请求前清空缓存区数据 +* 输入 : ClientSocket 客户端套接字 +* 输出 : 无 +*********************************************************************************************/ +void Clear_recv_buf(SOCKET clientSocket) { - SOCKET clientSocket = Init_client(IP, Port_number); - if (INVALID_SOCKET == clientSocket) + struct timeval tmOut; + tmOut.tv_sec = 0; + tmOut.tv_usec = 0; + fd_set fds; + FD_ZERO(&fds); + FD_SET(clientSocket, &fds); + int nRet; + char tmp[2]; + memset(tmp, 0, sizeof(tmp)); + while (1) { - cout << "ʼվʧ" << endl; + nRet = select(FD_SETSIZE, &fds, NULL, NULL, &tmOut); + if (nRet == 0) + break; + recv(clientSocket, tmp, 1, 0); + } +} + +void Printf_Coil_date(UINT8 *Response_Message) +{ + +} + +void Printf_Register_date(UINT8 *Response_Message) +{ + +} +void Printf_Anomaly_date(UINT8 *Response_Message) +{ + +} + +k + + +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)//先处理异常响应 + { + + return true; + } + else if (Response_Message[6] == Request_Message[6] && Response_Message_len - 5 == Response_Message[5]) //判断是否是正常响应帧 + { + + 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) { - char receiveBuf[260]; - memset(receiveBuf, 0, 100); - recv(clientSocket, receiveBuf, 100, 0); - printf("%s\n", receiveBuf); - send(clientSocket, "hello,this is client", strlen("hello,this is client") + 1, 0); + + 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 Message_len = Crate_TCP_Message(Request_Message, Function_code, Operations_Number, Starting_address, Write_date); + printf("主站请求 :"); + for (int i = 0; i < Message_len; i++) + { + printf("%02x ", Request_Message[i]); + } + printf("\n"); + Clear_recv_buf(ClientSocket); + send(ClientSocket, (char*)Request_Message, Message_len, 0); + memset(Response_Message, 0, 260); + int ret = recv(ClientSocket, (char*)Response_Message, 260, 0); + if (ret > 0) + { + printf("从站响应 :"); + for (int i = 0; i < ret; i++) + { + printf("%02x ", Response_Message[i]); + } + printf("\n"); + } + else + cout << "响应超时" << endl; } - //ر׽ - closesocket(clientSocket); - //رշ + //关闭套接字 + closesocket(ClientSocket); + //关闭服务 WSACleanup(); - return false; + return true; } diff --git a/Modbus_communication/Modbus_TCP/TCP_client.h b/Modbus_communication/Modbus_TCP/TCP_client.h index 8e40027..9f5b5e8 100644 --- a/Modbus_communication/Modbus_TCP/TCP_client.h +++ b/Modbus_communication/Modbus_TCP/TCP_client.h @@ -3,6 +3,12 @@ #include "common.h" -int Tcp_client(string IP, unsigned int Port_number); + + +bool InitSocket_Version(void); +bool Check_IP(char* IP); +void Input_IP(string& IP, unsigned int *Port_number); +bool Tcp_client(string IP, unsigned int Port_number); + #endif \ No newline at end of file diff --git a/Modbus_communication/Modbus_TCP/common.cpp b/Modbus_communication/Modbus_TCP/common.cpp index 55c16d9..8c5c83a 100644 --- a/Modbus_communication/Modbus_TCP/common.cpp +++ b/Modbus_communication/Modbus_TCP/common.cpp @@ -1,83 +1,5 @@ #include "common.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 - -} /********************************************************************************************* * 功能    : 选择功能码 @@ -118,7 +40,7 @@ unsigned int Input_Starting_address(void) { unsigned int Starting_address; int i = 1; - printf("请输入操作(十进制)起始地址 \n"); + cin >> dec; do { if (i == 1) @@ -148,6 +70,7 @@ unsigned int Input_Operations_Number(int Function_code) bool flage = true; printf(" 功能码 0x01 0x03 0x0F 0x10\n"); printf("操作数量 1-2000 1-125 1-1968 1-123\n"); + cin >> dec; do { if (i == 1) @@ -194,6 +117,7 @@ bool Check_Write_date(string Write_date, int Write_date_number) { Space_number++; j = i; + continue; } else return false; @@ -239,7 +163,7 @@ unsigned int Count_Write_date_number(int Function_code, unsigned int Operations_ * 输入 : Function_code 选择的功能码类型 Operations_Number对应功能码类型的操作数量 * 输出 : Write_date 写入的数据 *********************************************************************************************/ -string Write_date(int Function_code, unsigned int Operations_Number) +string Input_Write_date(int Function_code, unsigned int Operations_Number) { int i = 1; string Write_date; @@ -301,6 +225,8 @@ void Crate_MBAP(UINT8 *Message, int Function_code, unsigned int Operations_Numbe *********************************************************************************************/ int HexStringtoByte(UINT8 *Message, string Write_date, int Message_len) { + if (Write_date.length() == 0) + return Message_len; const char *b = Write_date.c_str(); for (int i = 0; i + 3 < Write_date.length(); i = i + 3) { diff --git a/Modbus_communication/Modbus_TCP/common.h b/Modbus_communication/Modbus_TCP/common.h index 7f9b972..5799a60 100644 --- a/Modbus_communication/Modbus_TCP/common.h +++ b/Modbus_communication/Modbus_TCP/common.h @@ -14,8 +14,15 @@ using namespace std; -bool Check_IP(char* IP); -bool InitSocket_Version(void); -void Input_IP(string& IP, unsigned int *Port_number); +int Input_Function_code(void); +unsigned int Input_Starting_address(void); +unsigned int Input_Operations_Number(int Function_code); +bool Check_Write_date(string Write_date, int Write_date_number); +unsigned int Count_Write_date_number(int Function_code, unsigned int Operations_Number); +string Input_Write_date(int Function_code, unsigned int Operations_Number); +void Crate_MBAP(UINT8 *Message, int Function_code, unsigned int Operations_Number); +int HexStringtoByte(UINT8 *Message, string Write_date, int Message_len); +int Crate_TCP_Message(UINT8 *Message, int Function_code, unsigned int Operations_Number, unsigned int Starting_address, string Write_date); + #endif \ No newline at end of file diff --git a/Modbus_communication/Modbus_TCP/main.cpp b/Modbus_communication/Modbus_TCP/main.cpp index 0dba8b0..c417351 100644 --- a/Modbus_communication/Modbus_TCP/main.cpp +++ b/Modbus_communication/Modbus_TCP/main.cpp @@ -1,15 +1,11 @@ #include "main.h" -#define DEVICE_ID 0x10 - int main() { - UINT8 Message[260]; - int Function_code = 0x10; - unsigned int Operations_Number = 5; - unsigned int Starting_address = 13; - string a = "1F 00 01 02 03 04 05 06 07 06"; - + string IP; + unsigned int Port; + Input_IP(IP,&Port); + Tcp_client(IP,Port); getchar(); return 0; } \ No newline at end of file