@利用c++多线程实现modbusTCP/ip协议远程读写服务器
主函数如下
#include<iostream>
#include"Modbus.h"
bool test01(ModBus &m1)
{
m1.ReadHolingRegisters(0, 60);
m1.WriteHolingRegisters(0, 60);
return 0;
}
void test02()
{
ModBus m1("192.168.1.185", 50200);
m1.ModBus_connect();
//ModBus m2("192.168.1.183", 50201);
//m2.ModBus_connect();
//ModBus m3("192.168.1.183", 50202);
//m3.ModBus_connect();
while (1)
{
std::thread thread1([&m1]() { test01(m1); });
//std::thread thread2([&m2]() { test01(m2); });
//std::thread thread3([&m3]() { test01(m3); });
thread1.join();
//thread2.join();
//thread3.join();
std::this_thread::sleep_for(std::chrono::seconds(2));
}
}
int main()
{
test02();
return 0;
}
Modbus.h 头文件
#pragma once
#include<vector>
#include <winsock.h>
#define _CRT_SECURE_NO_WARNINGS
#pragma comment(lib, "ws2_32.lib")
#include <thread>
#include <random>
#include <cstdint>
#include <cstring>
#include <random>
using namespace std;
class ModBus
{
public:
ModBus(string modbus_address, unsigned modbus_port);
bool ModBus_connect();
BOOL ReadHolingRegisters(USHORT start, USHORT length);
BOOL ReadHolingRegisters_int(USHORT start, USHORT length);
BOOL WriteHolingRegisters(USHORT start, USHORT length);
BOOL WriteHolingRegisters_int(USHORT start, USHORT length);
public:
SOCKET clientSocket;
string modbus_address;
unsigned modbus_port;
};
Modbus源文件
#pragma once
#include<iostream>
using namespace std;
#include<iostream>
#include"Modbus.h"
uint32_t swapEndianness(uint32_t value) {
return ((value & 0xFF) << 24) | (((value >> 8) & 0xFF) << 16) | (((value >> 16) & 0xFF) << 8) | ((value >> 24) & 0xFF);
}
ModBus::ModBus(string modbus_address, unsigned modbus_port)
{
this->modbus_address = modbus_address;
this->modbus_port = modbus_port;
}
bool ModBus:: ModBus_connect()
{
WSADATA wsaData; // 初始化WSADATA为后续调用做准备
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup 失败。" << std::endl;
return false;
}
// 创建套接字 通过套接字,程序能够连接到 Modbus 服务器,发送请求,接收响应,并在不需要连接时关闭套接字释放资源。
clientSocket = socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == INVALID_SOCKET) {
std::cerr << "Failed to create socket: " << WSAGetLastError() << std::endl;
return false;
}
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr((this->modbus_address).data()); // 服务器的 IP 地址
serverAddr.sin_port = htons(this->modbus_port);
/* if (bind(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) 服务器连接客户端
{
std::cerr << "Connect failed: " << WSAGetLastError() << std::endl;
closesocket(clientSocket);
return false;
}*/
if (connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
std::cerr << "Connect failed: " << WSAGetLastError() << std::endl;
closesocket(clientSocket);
return false;
}
cout << "连接成功" << endl;
cout << this->modbus_port << endl;
return TRUE;
}
BOOL ModBus::ReadHolingRegisters(USHORT start, USHORT length)
{
//五步走
//1.拼接报文
vector <char> send_data;
//事务协议 1个字节有8位置
send_data.push_back(0); send_data.push_back(0); send_data.push_back(0); send_data.push_back(0);
//长度
send_data.push_back(0); send_data.push_back(6);
//单元标识符
send_data.push_back(0x01);
//功能码
send_data.push_back(0x03);
//起始寄存器地址
send_data.push_back(char(start / 256));
send_data.push_back(char(start % 256));
//长度
send_data.push_back(char(length / 256));
send_data.push_back(char(length % 256));
//2.发送报文
const char* charData = &send_data[0];
int dataSizeToSend = send_data.size();
if (send(clientSocket, charData, dataSizeToSend, 0) == SOCKET_ERROR)
{
std::cerr << "Send failed: " << WSAGetLastError() << std::endl;
/*ModBus_connect();*/
return -1;
}
std::cout << "Data sent successfully." << std::endl;
//3.接收报文,接收数据
char buffer[1024];
int bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesRead == SOCKET_ERROR) {
std::cerr << "Receive failed: " << WSAGetLastError() << std::endl;
/*ModBus_connect();*/
return -1;
}
else {
std::cout << "Received " << bytesRead << " bytes." << std::endl;
}
//4.验证报文
if (bytesRead == 2 * length + 9)
{
//cout << "长度正确" << endl;
}
//5.解析报文 前9个字节是固定的不属于数据。
uint32_t* data = (uint32_t*)(buffer + 9);
for (int i = 0; i < (length / 2); i++)
{
data[i] = ntohl(data[i]);
}
cout << "当前端口为:" << this->modbus_port<< endl;
float* new_data = (float*)data;
for (int i = 0; i < (length / 2); i++)
{
cout << "data" << i + 1 << ":" << new_data[i] << " ";
}
cout << endl;
// 1个float 4个字节 转换;
//char dataBuffer[120];
//std::memcpy(dataBuffer, buffer + 9, 120);
//float values[30];
//for (int i = 0; i < 30; ++i) {
// uint32_t rawValue;
// std::memcpy(&rawValue, &dataBuffer[i * 4], sizeof(uint32_t));
// // 根据系统字节序转换字节顺序
// rawValue = swapEndianness(rawValue);
// std::memcpy(&values[i], &rawValue, sizeof(float));
//
//}
//for (int i = 0; i < 30; ++i) {
// std::cout << "Value " << ": " << values[i] << " ";
//}
//cout << endl;
//小端模式
//const float * data = (float*)(buffer + 9);
//float a;
//cout << "每个模块的值" << endl;
//for (int i = 0; i < (length/2); i++)
//{
// cout << (((*(data + i)))) << " ";
//}
//cout << endl;
return 1;
}
BOOL ModBus::WriteHolingRegisters(USHORT start, USHORT length)
{
//五步走
//1.拼接报文
vector <char> send_data;
//事务 1个字节有8位置
send_data.push_back(0); send_data.push_back(0);
//协议
send_data.push_back(0); send_data.push_back(0);
//长度
send_data.push_back(0); send_data.push_back(7 + 2 * length);
//单元标识符
send_data.push_back(0x01);
//功能码
send_data.push_back(0x10);
//起始寄存器地址
send_data.push_back(char(start / 256));
send_data.push_back(char(start % 256));
//寄存器数量
send_data.push_back(0);
send_data.push_back( length);
//字节计数 字节*2
send_data.push_back( 2*length);
//cout << send_data.size() << endl;
//长度 一个数据占四个字节
// 1.end
// 使用指针和类型转换将浮点数转换为字节数组
std::random_device rd;
std::mt19937 gen(rd());
// 定义生成浮点数的范围
float lower_bound = 0.0;
float upper_bound = 12.0;
// 创建均匀分布对象
for (int i = 0; i < (length / 2); i++)
{
std::uniform_real_distribution<float> distribution(lower_bound, upper_bound);
// 生成随机浮点数
float random_float = distribution(gen);
/*cout << "float数值:" << random_float<< endl;*/
uint32_t uintValue;
uintValue = *reinterpret_cast<uint32_t*>(&random_float);
uintValue = htonl(uintValue);
char* byteArray = (char*)(&uintValue); // 创建一个4字节的字节数组
for (int j = 0; j < 4; ++j)
{
send_data.push_back(byteArray[j]);
}
}
// (2)方法
根据系统字节序转换字节顺序
//std::uniform_real_distribution<float> distribution(lower_bound, upper_bound);
//float random_float = distribution(gen);
//float floatValue = random_float; // 浮点数值
//uint32_t new_rawValue;
//std::memcpy(&new_rawValue, &floatValue, sizeof(uint32_t));
//new_rawValue = swapEndianness(new_rawValue);
//char byteArray[4]; // 创建一个4字节的字节数组
//std::memcpy(byteArray, &new_rawValue, sizeof(floatValue));
//for (int j = 0; j < 4; ++j)
//{
// send_data.push_back(byteArray[j]);
//}
//2.发送报文
const char* charData = &send_data[0];
int dataSizeToSend = send_data.size();
if (send(clientSocket, charData, dataSizeToSend, 0) == SOCKET_ERROR)
{
std::cerr << "Send failed: " << WSAGetLastError() << std::endl;
/*ModBus_connect();*/
return -1;
}
//std::cout << "Data sent successfully." << std::endl;
//3.接收报文,接收数据
char buffer[1024];
int bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesRead == SOCKET_ERROR) {
std::cerr << "Receive failed: " << WSAGetLastError() << std::endl;
/*ModBus_connect();*/
return -1;
}
else {
//std::cout << "Received " << bytesRead << " bytes." << std::endl;
}
//4.验证报文
if (bytesRead == 12)
{
cout << "长度正确" << endl;
}
else
{
cout << bytesRead << endl;
cout << "长度不争取报文有问题" << endl;
}
return 1;
}
BOOL ModBus::ReadHolingRegisters_int(USHORT start, USHORT length)
{
//五步走
//1.拼接报文
vector <char> send_data;
//事务协议 1个字节有8位置
send_data.push_back(0); send_data.push_back(0); send_data.push_back(0); send_data.push_back(0);
//长度
send_data.push_back(0); send_data.push_back(6);
//单元标识符
send_data.push_back(0x01);
//功能码
send_data.push_back(0x03);
//起始寄存器地址
send_data.push_back(char(start / 256));
send_data.push_back(char(start % 256));
//长度
send_data.push_back(char(length / 256));
send_data.push_back(char(length % 256));
//2.发送报文
const char* charData = &send_data[0];
int dataSizeToSend = send_data.size();
if (send(clientSocket, charData, dataSizeToSend, 0) == SOCKET_ERROR)
{
std::cerr << "Send failed: " << WSAGetLastError() << std::endl;
return -1;
}
std::cout << "Data sent successfully." << std::endl;
//3.接收报文,接收数据
char buffer[1024];
int bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesRead == SOCKET_ERROR) {
std::cerr << "Receive failed: " << WSAGetLastError() << std::endl;
return -1;
}
else {
std::cout << "Received " << bytesRead << " bytes." << std::endl;
}
//4.验证报文
if (bytesRead == 2 * length + 9)
{
//cout << "长度正确" << endl;
}
//5.解析报文 前9个字节是固定的不属于数据。
int16_t* data = (int16_t*)(buffer + 9);
for (int i = 0; i < (length ); i++)
{
data[i] = ntohs(data[i]);
cout << "data" << i + 1 << ":" << data[i] << " ";
}
cout << endl;
return 1;
}
BOOL ModBus::WriteHolingRegisters_int(USHORT start, USHORT length)
{
//五步走
//1.拼接报文
vector <char> send_data;
//事务 1个字节有8位置
send_data.push_back(0); send_data.push_back(0);
//协议
send_data.push_back(0); send_data.push_back(0);
//长度
send_data.push_back(0); send_data.push_back(7 + 2 * length);
//单元标识符
send_data.push_back(0x01);
//功能码
send_data.push_back(0x10);
//起始寄存器地址
send_data.push_back(char(start / 256));
send_data.push_back(char(start % 256));
//寄存器数量
send_data.push_back(0);
send_data.push_back(length);
//字节计数 字节*2
send_data.push_back(2 * length);
//长度 一个数据占四个字节
// 定义生成浮点数的范围
float lower_bound = 0.0;
float upper_bound = 12.0;
// 创建均匀分布对象
for (int i = 0; i < (length ); i++)
{
std::random_device rd;
std::mt19937 gen(rd());
// 设置种子以确保每次运行生成不同的随机数序列
std::srand(static_cast<unsigned int>(std::time(nullptr)));
// 生成随机整数在 [0, 100] 范围内
int randomNumber = std::rand() % 101; // 取模操作将结果限制在 [0, 100] 范围内
uint16_t uintValue;
uintValue = *reinterpret_cast<uint16_t*>(&randomNumber);
uintValue = htons(uintValue);
char* byteArray = (char*)(&uintValue); // 创建一个2字节的字节数组
for (int j = 0; j < 2; j++)
{
send_data.push_back(byteArray[j]);
}
}
//2.发送报文
const char* charData = &send_data[0];
int dataSizeToSend = send_data.size();
if (send(clientSocket, charData, dataSizeToSend, 0) == SOCKET_ERROR)
{
std::cerr << "Send failed: " << WSAGetLastError() << std::endl;
return -1;
}
//std::cout << "Data sent successfully." << std::endl;
//3.接收报文,接收数据
char buffer[1024];
int bytesRead = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesRead == SOCKET_ERROR) {
std::cerr << "Receive failed: " << WSAGetLastError() << std::endl;
return -1;
}
else {
//std::cout << "Received " << bytesRead << " bytes." << std::endl;
}
//4.验证报文
if (bytesRead == 12)
{
cout << "长度正确" << endl;
}
else
{
cout << bytesRead << endl;
cout << "长度不争取报文有问题" << endl;
}
return 1;
}