c++编写modbusTCP/ip协议远程读写服务器

文章介绍了如何使用C++编程语言,通过多线程技术实现ModbusTCP/IP协议的远程设备读写功能,包括连接服务器、发送和接收报文以及数据处理。
摘要由CSDN通过智能技术生成

@利用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;
	
	}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值