@@ -83,6 +83,41 @@ bool SendData(HANDLE m_hcomm, char* data, int len) | |||||
return true; | 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"); | printf("\n"); | ||||
} | } | ||||
HANDLE Input_Parameter() | |||||
HANDLE Input_Parameter(void) | |||||
{ | { | ||||
HANDLE handle_com; | HANDLE handle_com; | ||||
while (true) | while (true) | ||||
@@ -495,39 +530,4 @@ void Printf_Message(UINT8 *Message, int flage, int message_len) | |||||
Log_Note(Message, flage, 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; | |||||
} | |||||
@@ -14,17 +14,12 @@ using namespace std; | |||||
#define LOG_NOTE_SWITCH 1 | #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); | 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 | #endif |
@@ -1,117 +1,5 @@ | |||||
#include "TCP_client.h" | #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); | 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) | 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); | 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; | break; | ||||
} | } | ||||
int Response_Message_len = Recv_date(clientSocket, Response_Message);//接收 | 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 (Response_Message_len) | ||||
{ | { | ||||
if (!Analysis_Response_Message(Response_Message, Request_Message, Response_Message_len)) | if (!Analysis_Response_Message(Response_Message, Request_Message, Response_Message_len)) | ||||
@@ -1,5 +1,65 @@ | |||||
#include "common.h" | #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; | return true; | ||||
} | } | ||||
/********************************************************************************************* | /********************************************************************************************* | ||||
* 功能 : 计算写入数据的字节数 | * 功能 : 计算写入数据的字节数 | ||||
* 描述 : 通过对应的功能码和操作数量计算对应的数据字节数 | * 描述 : 通过对应的功能码和操作数量计算对应的数据字节数 | ||||
* 输入 : function_code 选择的功能码类型 operations_Number对应功能码类型的操作数量 | * 输入 : function_code 选择的功能码类型 operations_Number对应功能码类型的操作数量 | ||||
* 输出 : Write_date_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; | unsigned int write_date_number = 0; | ||||
if (function_code == 0x01 || function_code == 0x03) | 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) //读线圈 | if (function_code == 0x0F) //读线圈 | ||||
{ | { | ||||
write_date_number = function_code / 8; | write_date_number = function_code / 8; | ||||
if (operations_Number % 8) | |||||
if (operations_number % 8) | |||||
write_date_number++; | write_date_number++; | ||||
} | } | ||||
if (function_code == 0x10) | if (function_code == 0x10) | ||||
write_date_number = operations_Number * 2; | |||||
write_date_number = operations_number * 2; | |||||
return write_date_number; | return write_date_number; | ||||
} | } | ||||
@@ -165,19 +224,19 @@ unsigned int Count_Write_date_number(int function_code, unsigned int operations_ | |||||
* 输入 : Function_code 选择的功能码类型 Operations_Number对应功能码类型的操作数量 | * 输入 : Function_code 选择的功能码类型 Operations_Number对应功能码类型的操作数量 | ||||
* 输出 : Respone_len 预期响应的数据字节数 | * 输出 : 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; | unsigned int respone_len = 0; | ||||
if (function_code == 0x0F || function_code == 0x10) | if (function_code == 0x0F || function_code == 0x10) | ||||
return respone_len; | return respone_len; | ||||
if (function_code == 0x01) //读线圈 | if (function_code == 0x01) //读线圈 | ||||
{ | { | ||||
respone_len = operations_Number / 8; | |||||
if (operations_Number % 8) | |||||
respone_len = operations_number / 8; | |||||
if (operations_number % 8) | |||||
respone_len++; | respone_len++; | ||||
} | } | ||||
if (function_code == 0x03) | if (function_code == 0x03) | ||||
respone_len = operations_Number * 2; | |||||
respone_len = operations_number * 2; | |||||
return respone_len; | return respone_len; | ||||
} | } | ||||
@@ -213,85 +272,6 @@ string Input_Write_date(int function_code, unsigned int operations_Number) | |||||
return write_date; | 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 报文数据长度 | * Message_len 报文数据长度 | ||||
* 输出 : 无 | * 输出 : 无 | ||||
*********************************************************************************************/ | *********************************************************************************************/ | ||||
void Log_Note(UINT8 *Message, int flage, int message_len) | void Log_Note(UINT8 *Message, int flage, int message_len) | ||||
{ | { | ||||
FILE *fp = NULL; | FILE *fp = NULL; | ||||
@@ -339,3 +318,137 @@ void Log_Note(UINT8 *Message, int flage, int message_len) | |||||
fclose(fp); | fclose(fp); | ||||
fp = NULL; | 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; | |||||
} |
@@ -21,9 +21,14 @@ unsigned int Input_Starting_address(void); | |||||
unsigned int Input_Operations_number(int function_code); | unsigned int Input_Operations_number(int function_code); | ||||
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); | ||||
string Input_Write_date(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); | 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 | #endif |