From 5fa8c62734f189137520e7164acd514734919c96 Mon Sep 17 00:00:00 2001 From: zcn1123 <2363211205@qq.com> Date: Wed, 16 Sep 2020 22:36:02 +0800 Subject: [PATCH] =?UTF-8?q?=20=20=E8=B0=83=E6=95=B4TCP/RTU=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Modbus_RTU_Salve/common.cpp | 72 ++--- .../Modbus_RTU_Salve/common.h | 17 +- .../Modbus_TCP/TCP_client.cpp | 254 +++++---------- Modbus_communication/Modbus_TCP/common.cpp | 291 ++++++++++++------ Modbus_communication/Modbus_TCP/common.h | 9 +- 5 files changed, 322 insertions(+), 321 deletions(-) diff --git a/Modbus_communication/Modbus_RTU_Salve/common.cpp b/Modbus_communication/Modbus_RTU_Salve/common.cpp index 159a6b7..7b5d279 100644 --- a/Modbus_communication/Modbus_RTU_Salve/common.cpp +++ b/Modbus_communication/Modbus_RTU_Salve/common.cpp @@ -83,6 +83,41 @@ bool SendData(HANDLE m_hcomm, char* data, int len) return true; } +bool Abnormal_Connection(HANDLE *handle_com) +{ + printf("设备端口异常,请检查设备连接状态\n"); + printf("**************************** Press Enter To Contioun ****************************\n"); + getchar(); + system("cls"); + printf("是否重新连接端口: 1 重新连接 0 关闭本软件\n"); + int flage = 0; + do + { + cin >> flage; + cin.clear(); + cin.sync(); + } while (!(flage == 0 || flage == 1)); + if (flage == 0) + { + return false; + } + CloseHandle(*handle_com); + *handle_com = Input_Parameter(); + return true; +} + +bool Recv_date(HANDLE *handle_com, UINT8 *Requst_Message, DWORD *read_len) +{ + PurgeComm(*handle_com, PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT);//清除缓存 + BOOL read_flage = ReadFile(*handle_com, Requst_Message, 300, &(*read_len), NULL); //阻塞等待接收请求报文 + if (read_flage && (*read_len > 0)) + { + return true; + } + if (!Abnormal_Connection(handle_com)) + return false; + return true; +} /********************************************************************************************* * 功能     :  检查端口名称 * 描述    : 判断端口名称是否正确 @@ -455,7 +490,7 @@ void GetComm_Name(void) printf("\n"); } -HANDLE Input_Parameter() +HANDLE Input_Parameter(void) { HANDLE handle_com; while (true) @@ -495,39 +530,4 @@ void Printf_Message(UINT8 *Message, int flage, int message_len) Log_Note(Message, flage, message_len); } -bool Abnormal_Connection(HANDLE *handle_com) -{ - printf("设备端口异常,请检查设备连接状态\n"); - printf("**************************** Press Enter To Contioun ****************************\n"); - getchar(); - system("cls"); - printf("是否重新连接端口: 1 重新连接 0 关闭本软件\n"); - int flage = 0; - do - { - cin >> flage; - cin.clear(); - cin.sync(); - } while (!(flage == 0 || flage == 1)); - if (flage == 0) - { - return false; - } - CloseHandle(*handle_com); - *handle_com = Input_Parameter(); - return true; -} - -bool Recv_date(HANDLE *handle_com, UINT8 *Requst_Message, DWORD *read_len) -{ - PurgeComm(*handle_com, PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT);//清除缓存 - BOOL read_flage = ReadFile(*handle_com, Requst_Message, 300, &(*read_len), NULL); //阻塞等待接收请求报文 - if (read_flage && (*read_len > 0)) - { - return true; - } - if (!Abnormal_Connection(handle_com)) - return false; - return true; -} diff --git a/Modbus_communication/Modbus_RTU_Salve/common.h b/Modbus_communication/Modbus_RTU_Salve/common.h index 7e5d743..39e3661 100644 --- a/Modbus_communication/Modbus_RTU_Salve/common.h +++ b/Modbus_communication/Modbus_RTU_Salve/common.h @@ -14,17 +14,12 @@ using namespace std; #define LOG_NOTE_SWITCH 1 -unsigned int Count_Read_date_number(int function_code, unsigned int operations_Number); -HANDLE Init_COM(LPCTSTR Port, int baud_rate, BYTE date_bits, BYTE stop_bit, BYTE parity); +HANDLE Input_Parameter(void); +void Printf_Message(UINT8 *Message, int flage, int message_len); +UINT16 CRC_16(UINT8 *data, unsigned int crc_len); +unsigned int Count_Read_date_number(int function_code, unsigned int operations_number); bool SendData(HANDLE m_hcomm, char* data, int len); -string Input_COMM(void); -unsigned int Input_Baud_Rate(void); -BYTE Input_Date_Bits(void); -BYTE Input_Stop_Bits(BYTE date_bits); -BYTE Input_Parity(void); -unsigned int Input_RTU_Enable(void); -UINT16 CRC_16(UINT8 *data, unsigned int crc_Len); -void Log_Note(UINT8 *Message, int flage, int message_len); -void GetComm_Name(void); +bool Recv_date(HANDLE *handle_com, UINT8 *Requst_Message, DWORD *read_len); + #endif \ No newline at end of file diff --git a/Modbus_communication/Modbus_TCP/TCP_client.cpp b/Modbus_communication/Modbus_TCP/TCP_client.cpp index 7149df4..037c6ca 100644 --- a/Modbus_communication/Modbus_TCP/TCP_client.cpp +++ b/Modbus_communication/Modbus_TCP/TCP_client.cpp @@ -1,117 +1,5 @@ #include "TCP_client.h" - - -/********************************************************************************************* -* 功能    : socket版本 -* 描述   : 启动socket服务 -* 输入 : 无 -* 输出 : true 启动成功 -* false 启动失败 -*********************************************************************************************/ -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]; - 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 ,端口号范围1---65535 - -} - -/********************************************************************************************* -* 功能    : 初始化客户端 -* 描述   : 根据终端输入从站IP地址和端口号连接对应的服务器,设置超时时间 -* 输入 : 无 -* 输出 : ClientSocket 连接成功的套接字 -*********************************************************************************************/ -SOCKET Init_Client() -{ - if (InitSocket_Version() == 0) - { - printf("启动Socket服务失败,请检查Socket版本"); - return INVALID_SOCKET; - } - string ip_address; - unsigned int port_number; - Input_IP(ip_address, &port_number); - SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0); - sockaddr_in serversock_in; - serversock_in.sin_addr.S_un.S_addr = inet_addr(ip_address.c_str()); - serversock_in.sin_family = AF_INET; - serversock_in.sin_port = htons(port_number); - if (SOCKET_ERROR == connect(clientSocket, (SOCKADDR*)&serversock_in, sizeof(SOCKADDR))) - { - cout << "尝试连接TCP从站失败" << endl; - return INVALID_SOCKET; - } - cout << "连接TCP从站成功" << endl; - TIMEVAL timeout; - timeout.tv_sec = 200; //ms - timeout.tv_usec = 0; //us - setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));//设置接收超时时间 - return clientSocket; -} +UINT16 Transmission_Indicator = 0x00; //事务号 /********************************************************************************************* * 功能    : 打印读取从站的线圈状态 @@ -256,25 +144,6 @@ bool Analysis_Response_Message(UINT8 *Response_Message, UINT8 *Request_Message, return Printf_Analysis_Outcome(Response_Message, Request_Message); } -void Clear_buf(SOCKET clientSocket) -{ - unsigned long bytesToRecv; - char temp[500]; - do - { - ioctlsocket(clientSocket, FIONREAD, &bytesToRecv); - if (bytesToRecv != 0)//不等于0时进行清理操作 - { - if (bytesToRecv > 500) - { - recv(clientSocket, temp, 500, 0); - } - else - recv(clientSocket, temp, bytesToRecv, 0); - } - } while (bytesToRecv != 0); - -} void Printf_Message(UINT8 *Message,int flage, int message_len) { @@ -291,69 +160,86 @@ void Printf_Message(UINT8 *Message,int flage, int message_len) Log_Note(Message, flage, message_len); } -bool Send_date(SOCKET clientSocket, UINT8 *Request_Message, int request_message_len) -{ - Clear_buf(clientSocket); //清理缓冲区 - int status = send(clientSocket, (char*)Request_Message, request_message_len, 0); - if (status == (-1)) - { - return false; - } - Printf_Message(Request_Message, 1, request_message_len); - return true; -} -bool Abnormal_Connection(SOCKET *clientSocket) +/********************************************************************************************* +* 功能    : 生成MBAP报头 +* 描述 : MBAP报文头的包括的内容: +* +-------------+---------+--------+--------+------------------------------+ +* | 域 | 长度 | 客户机 | 服务器 | 描述 | +* +-------------+---------+--------+--------+------------------------------+ +* |事务元标识符 | 2个字节 | 启动 | 复制 |请求/响应事务处理的识别码 | +* +-------------+---------+--------+--------+------------------------------+ +* |协议标识符 | 2个字节 | 启动 | 复制 |0=MODBUS 协议 | +* +-------------+---------+--------+--------+------------------------------+ +* | 长度 | 2个字节 | 启动 | 启动 |以下字节的数量 | +* +-------------+---------+--------+--------+------------------------------+ +* |单元标识符 | 1个字节 | 启动 | 复制 |连接的远程从站的识别码 | +* 输入 : 无 +* 输出 : MBAP报文头内容 +*********************************************************************************************/ +void Create_MBAP(UINT8 *Message, int function_code, unsigned int operations_number) { - printf("连接异常,请检查连接状态。\n"); - printf("**************************** Press Enter To Contioun ****************************\n"); - getchar(); - system("cls"); - closesocket(*clientSocket); - WSACleanup(); - printf("是否重新连接服务器: 1 重新连接 0 关闭本软件\n"); - int flage = 0; - do - { - cin >> flage; - cin.clear(); - cin.sync(); - } while (!(flage == 0 || flage == 1)); - if (flage == 0) - return false; - system("cls"); - do + Message[0] = Transmission_Indicator >> 8;//事务号 + Message[1] = (UINT8)Transmission_Indicator; + Transmission_Indicator++; + Message[2] = 0x00; //Modbus协议标识 + Message[3] = 0x00; + Message[4] = 0x00;//后续字节长度 + Message[5] = Count_Write_date_number(function_code, operations_number) + 0x06; + if (function_code == 0x0F || function_code == 0x10)//0f/10功能码后续字节数多1 { - *clientSocket = Init_Client(); - } while (INVALID_SOCKET == *clientSocket); - system("cls"); - return true; + Message[5] = Message[5] + 1; + } + Message[6] = DEVICE_ID; } -int Recv_date(SOCKET clientSocket, UINT8 *Response_Message) +/********************************************************************************************* +* 功能    : 字符串转UINT8类型 +* 描述   : 根据写入数量和功能码类型输入相应的数据 +* 输入 : *Message 消息帧存放的数组 Write_date 要转换的字符串 +* Message_len消息帧数组的起始位置 +* 输出 : Message_len 消息帧的长度 +*********************************************************************************************/ +int HexStringtoByte(UINT8 *Message, string write_date, int message_len, int function_code, unsigned int operations_Number) { - int Response_Message_len = recv(clientSocket, (char*)Response_Message, 600, 0); - if (Response_Message_len > 0) + if (write_date.length() == 0) + return message_len; + Message[message_len] = Count_Write_date_number(function_code, operations_Number); + message_len++; + const char *b = write_date.c_str(); + int temp = 0; + for (unsigned int i = 0; i + 3 < write_date.length(); i = i + 3) { - Printf_Message(Response_Message, 0, Response_Message_len); - return Response_Message_len; + sscanf_s(b + i, "%02X", &temp); + Message[message_len] = (UINT8)temp; + message_len++; } - return 0; + sscanf_s(b + write_date.length() - 2, "%02X", &temp); + Message[message_len] = (UINT8)temp; + return ++message_len; } -bool Test_Connection_status(SOCKET clientSocket) +/********************************************************************************************* +* 功能    : 生成TCP模式下的消息帧 +* 描述   : 根据要写入的数据生成消息帧 +* 输入 : *Message 消息帧存放的数组 Write_date 写入数据的字符串 +* Function_code 功能码 Operations_Number 操作数量 Starting_address起始地址 +* 输出 : 消息帧的总长度 +*********************************************************************************************/ +int Create_TCP_Message(UINT8 *Message, int function_code, unsigned int operations_Number, unsigned int starting_address, string write_date) { - TIMEVAL timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 0; - fd_set reads; - FD_ZERO(&reads); - FD_SET(clientSocket, &reads); - if (select(0, &reads, 0, 0, &timeout)) - return false; - else - return true; + + Create_MBAP(Message, function_code, operations_Number); + Message[7] = function_code;//功能码 + Message[8] = starting_address >> 8;//起始地址H + Message[9] = starting_address;//起始地址L + Message[10] = operations_Number >> 8;//操作数量H + Message[11] = operations_Number;//操作数量L + + return HexStringtoByte(Message, write_date, 12, function_code, operations_Number); + } + /********************************************************************************************* * 功能    : 运行客户端 * 描述   : 初始化并且生成发送请求等待响应 @@ -388,6 +274,8 @@ int Tcp_Client() break; } int Response_Message_len = Recv_date(clientSocket, Response_Message);//接收 + Printf_Message(Request_Message, 1, request_message_len); + Printf_Message(Response_Message, 0, Response_Message_len); if (Response_Message_len) { if (!Analysis_Response_Message(Response_Message, Request_Message, Response_Message_len)) diff --git a/Modbus_communication/Modbus_TCP/common.cpp b/Modbus_communication/Modbus_TCP/common.cpp index bc874ad..d2b9ac6 100644 --- a/Modbus_communication/Modbus_TCP/common.cpp +++ b/Modbus_communication/Modbus_TCP/common.cpp @@ -1,5 +1,65 @@ #include "common.h" -UINT16 Transmission_Indicator = 0x00; //事务号 + + +/********************************************************************************************* +* 功能    : IP地址有效性检测 +* 描述   : 检测输入的IP地址是否合法 +* 输入 : IP 输入的IP地址 +* 输出 : true IP地址合法 +* false IP地址非法 +*********************************************************************************************/ +bool Check_IP(string ip) +{ + int s[4]; + 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 ,端口号范围1---65535 + +} /********************************************************************************************* * 功能    : 选择功能码 @@ -136,14 +196,13 @@ bool Check_Write_date(string write_date, int write_date_number) return true; } - /********************************************************************************************* * 功能    : 计算写入数据的字节数 * 描述   : 通过对应的功能码和操作数量计算对应的数据字节数 * 输入 : function_code 选择的功能码类型 operations_Number对应功能码类型的操作数量 * 输出 : Write_date_number 写入数据的字节数 *********************************************************************************************/ -unsigned int Count_Write_date_number(int function_code, unsigned int operations_Number) +unsigned int Count_Write_date_number(int function_code, unsigned int operations_number) { unsigned int write_date_number = 0; if (function_code == 0x01 || function_code == 0x03) @@ -151,11 +210,11 @@ unsigned int Count_Write_date_number(int function_code, unsigned int operations_ if (function_code == 0x0F) //读线圈 { write_date_number = function_code / 8; - if (operations_Number % 8) + if (operations_number % 8) write_date_number++; } if (function_code == 0x10) - write_date_number = operations_Number * 2; + write_date_number = operations_number * 2; return write_date_number; } @@ -165,19 +224,19 @@ unsigned int Count_Write_date_number(int function_code, unsigned int operations_ * 输入 : Function_code 选择的功能码类型 Operations_Number对应功能码类型的操作数量 * 输出 : Respone_len 预期响应的数据字节数 *********************************************************************************************/ -unsigned int Count_Respone_Len(int function_code, unsigned int operations_Number) +unsigned int Count_Respone_Len(int function_code, unsigned int operations_number) { unsigned int respone_len = 0; if (function_code == 0x0F || function_code == 0x10) return respone_len; if (function_code == 0x01) //读线圈 { - respone_len = operations_Number / 8; - if (operations_Number % 8) + respone_len = operations_number / 8; + if (operations_number % 8) respone_len++; } if (function_code == 0x03) - respone_len = operations_Number * 2; + respone_len = operations_number * 2; return respone_len; } @@ -213,85 +272,6 @@ string Input_Write_date(int function_code, unsigned int operations_Number) return write_date; } -/********************************************************************************************* -* 功能    : 生成MBAP报头 -* 描述 : MBAP报文头的包括的内容: -* +-------------+---------+--------+--------+------------------------------+ -* | 域 | 长度 | 客户机 | 服务器 | 描述 | -* +-------------+---------+--------+--------+------------------------------+ -* |事务元标识符 | 2个字节 | 启动 | 复制 |请求/响应事务处理的识别码 | -* +-------------+---------+--------+--------+------------------------------+ -* |协议标识符 | 2个字节 | 启动 | 复制 |0=MODBUS 协议 | -* +-------------+---------+--------+--------+------------------------------+ -* | 长度 | 2个字节 | 启动 | 启动 |以下字节的数量 | -* +-------------+---------+--------+--------+------------------------------+ -* |单元标识符 | 1个字节 | 启动 | 复制 |连接的远程从站的识别码 | -* 输入 : 无 -* 输出 : MBAP报文头内容 -*********************************************************************************************/ -void Create_MBAP(UINT8 *Message, int function_code, unsigned int operations_number) -{ - Message[0] = Transmission_Indicator >> 8;//事务号 - Message[1] = (UINT8)Transmission_Indicator; - Transmission_Indicator++; - Message[2] = 0x00; //Modbus协议标识 - Message[3] = 0x00; - Message[4] = 0x00;//后续字节长度 - Message[5] = Count_Write_date_number(function_code, operations_number) + 0x06; - if (function_code == 0x0F || function_code == 0x10)//0f/10功能码后续字节数多1 - { - Message[5] = Message[5] + 1; - } - Message[6] = DEVICE_ID; -} - -/********************************************************************************************* -* 功能    : 字符串转UINT8类型 -* 描述   : 根据写入数量和功能码类型输入相应的数据 -* 输入 : *Message 消息帧存放的数组 Write_date 要转换的字符串 -* Message_len消息帧数组的起始位置 -* 输出 : Message_len 消息帧的长度 -*********************************************************************************************/ -int HexStringtoByte(UINT8 *Message, string write_date, int message_len, int function_code, unsigned int operations_Number) -{ - if (write_date.length() == 0) - return message_len; - Message[message_len] = Count_Write_date_number(function_code, operations_Number); - message_len++; - const char *b = write_date.c_str(); - int temp = 0; - for (unsigned int i = 0; i + 3 < write_date.length(); i = i + 3) - { - sscanf_s(b + i, "%02X", &temp); - Message[message_len] = (UINT8)temp; - message_len++; - } - sscanf_s(b + write_date.length() - 2, "%02X",&temp); - Message[message_len] = (UINT8)temp; - return ++message_len; -} - -/********************************************************************************************* -* 功能    : 生成TCP模式下的消息帧 -* 描述   : 根据要写入的数据生成消息帧 -* 输入 : *Message 消息帧存放的数组 Write_date 写入数据的字符串 -* Function_code 功能码 Operations_Number 操作数量 Starting_address起始地址 -* 输出 : 消息帧的总长度 -*********************************************************************************************/ -int Create_TCP_Message(UINT8 *Message, int function_code, unsigned int operations_Number, unsigned int starting_address, string write_date) -{ - - Create_MBAP(Message, function_code, operations_Number); - Message[7] = function_code;//功能码 - Message[8] = starting_address >> 8;//起始地址H - Message[9] = starting_address;//起始地址L - Message[10] = operations_Number >> 8;//操作数量H - Message[11] = operations_Number;//操作数量L - - return HexStringtoByte(Message, write_date, 12, function_code, operations_Number); - -} - /********************************************************************************************* * 功能    : 日志记录 * 描述   : 记录每次通信的请求和响应报文 @@ -299,7 +279,6 @@ int Create_TCP_Message(UINT8 *Message, int function_code, unsigned int operation * Message_len 报文数据长度 * 输出 : 无 *********************************************************************************************/ - void Log_Note(UINT8 *Message, int flage, int message_len) { FILE *fp = NULL; @@ -339,3 +318,137 @@ void Log_Note(UINT8 *Message, int flage, int message_len) fclose(fp); fp = NULL; } + +/********************************************************************************************* +* 功能    : socket版本 +* 描述   : 启动socket服务 +* 输入 : 无 +* 输出 : true 启动成功 +* false 启动失败 +*********************************************************************************************/ +bool InitSocket_Version(void) +{ + WORD sockVersion = MAKEWORD(2, 2);//使用winsocket2.2版本 + WSADATA wsaData; + if (WSAStartup(sockVersion, &wsaData) != 0) + { + return false; + } + return true; +} + +/********************************************************************************************* +* 功能    : 初始化客户端 +* 描述   : 根据终端输入从站IP地址和端口号连接对应的服务器,设置超时时间 +* 输入 : 无 +* 输出 : ClientSocket 连接成功的套接字 +*********************************************************************************************/ +SOCKET Init_Client(void) +{ + if (InitSocket_Version() == 0) + { + printf("启动Socket服务失败,请检查Socket版本"); + return INVALID_SOCKET; + } + string ip_address; + unsigned int port_number; + Input_IP(ip_address, &port_number); + SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, 0); + sockaddr_in serversock_in; + serversock_in.sin_addr.S_un.S_addr = inet_addr(ip_address.c_str()); + serversock_in.sin_family = AF_INET; + serversock_in.sin_port = htons(port_number); + if (SOCKET_ERROR == connect(clientSocket, (SOCKADDR*)&serversock_in, sizeof(SOCKADDR))) + { + cout << "尝试连接TCP从站失败" << endl; + return INVALID_SOCKET; + } + cout << "连接TCP从站成功" << endl; + TIMEVAL timeout; + timeout.tv_sec = 200; //ms + timeout.tv_usec = 0; //us + setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));//设置接收超时时间 + return clientSocket; +} + +void Clear_buf(SOCKET clientSocket) +{ + unsigned long bytesToRecv; + char temp[500]; + do + { + ioctlsocket(clientSocket, FIONREAD, &bytesToRecv); + if (bytesToRecv != 0)//不等于0时进行清理操作 + { + if (bytesToRecv > 500) + { + recv(clientSocket, temp, 500, 0); + } + else + recv(clientSocket, temp, bytesToRecv, 0); + } + } while (bytesToRecv != 0); + +} + +bool Send_date(SOCKET clientSocket, UINT8 *Request_Message, int request_message_len) +{ + Clear_buf(clientSocket); //清理缓冲区 + int status = send(clientSocket, (char*)Request_Message, request_message_len, 0); + if (status == (-1)) + { + return false; + } + return true; +} + +bool Abnormal_Connection(SOCKET *clientSocket) +{ + printf("连接异常,请检查连接状态。\n"); + printf("**************************** Press Enter To Contioun ****************************\n"); + getchar(); + system("cls"); + closesocket(*clientSocket); + WSACleanup(); + printf("是否重新连接服务器: 1 重新连接 0 关闭本软件\n"); + int flage = 0; + do + { + cin >> flage; + cin.clear(); + cin.sync(); + } while (!(flage == 0 || flage == 1)); + if (flage == 0) + return false; + system("cls"); + do + { + *clientSocket = Init_Client(); + } while (INVALID_SOCKET == *clientSocket); + system("cls"); + return true; +} + +int Recv_date(SOCKET clientSocket, UINT8 *Response_Message) +{ + int Response_Message_len = recv(clientSocket, (char*)Response_Message, 600, 0); + if (Response_Message_len > 0) + { + return Response_Message_len; + } + return 0; +} + +bool Test_Connection_status(SOCKET clientSocket) +{ + TIMEVAL timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + fd_set reads; + FD_ZERO(&reads); + FD_SET(clientSocket, &reads); + if (select(0, &reads, 0, 0, &timeout)) + return false; + else + return true; +} \ No newline at end of file diff --git a/Modbus_communication/Modbus_TCP/common.h b/Modbus_communication/Modbus_TCP/common.h index 7dd2055..ffa055d 100644 --- a/Modbus_communication/Modbus_TCP/common.h +++ b/Modbus_communication/Modbus_TCP/common.h @@ -21,9 +21,14 @@ unsigned int Input_Starting_address(void); unsigned int Input_Operations_number(int function_code); unsigned int Count_Write_date_number(int function_code, unsigned int operations_Number); string Input_Write_date(int function_code, unsigned int operations_Number); -int Create_TCP_Message(UINT8 *Message, int function_code, unsigned int operations_Number, unsigned int starting_address, string write_date); + +unsigned int Count_Respone_Len(int function_code, unsigned int operations_number); void Log_Note(UINT8 *Message, int flage, int message_len); -unsigned int Count_Respone_Len(int function_code, unsigned int operations_Number); +SOCKET Init_Client(void); +bool Send_date(SOCKET clientSocket, UINT8 *Request_Message, int request_message_len); +bool Abnormal_Connection(SOCKET *clientSocket); +int Recv_date(SOCKET clientSocket, UINT8 *Response_Message); +bool Test_Connection_status(SOCKET clientSocket); #endif \ No newline at end of file