2025-06-08 12:48:04 +08:00
|
|
|
|
#ifndef MODBUS_TCP_SERVER_H
|
|
|
|
|
|
#define MODBUS_TCP_SERVER_H
|
|
|
|
|
|
|
|
|
|
|
|
#include "IYModbusTCPServer.h"
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
#include <thread>
|
|
|
|
|
|
#include <mutex>
|
|
|
|
|
|
#include <atomic>
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
|
#include <unordered_map>
|
|
|
|
|
|
|
2025-06-17 00:37:05 +08:00
|
|
|
|
// Platform-specific includes for socket operations
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
|
#include <winsock2.h>
|
|
|
|
|
|
#include <ws2tcpip.h>
|
|
|
|
|
|
#pragma comment(lib, "ws2_32.lib")
|
|
|
|
|
|
#else
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
|
#include <sys/select.h>
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
2025-06-08 12:48:04 +08:00
|
|
|
|
// libmodbus headers
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
|
#include "modbus.h"
|
|
|
|
|
|
#include "modbus-tcp.h"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class ModbusTCPServer : public IYModbusTCPServer {
|
|
|
|
|
|
private:
|
|
|
|
|
|
// 客户端连接结构体
|
|
|
|
|
|
struct ClientConnection {
|
|
|
|
|
|
int socket;
|
|
|
|
|
|
modbus_t* modbusCtx;
|
|
|
|
|
|
|
|
|
|
|
|
ClientConnection(int sock, modbus_t* ctx) : socket(sock), modbusCtx(ctx) {}
|
|
|
|
|
|
|
|
|
|
|
|
~ClientConnection() {
|
|
|
|
|
|
if (modbusCtx) {
|
|
|
|
|
|
modbus_free(modbusCtx);
|
|
|
|
|
|
}
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
|
if (socket != -1) {
|
|
|
|
|
|
closesocket(socket);
|
|
|
|
|
|
}
|
|
|
|
|
|
#else
|
|
|
|
|
|
if (socket != -1) {
|
|
|
|
|
|
close(socket);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
ModbusTCPServer();
|
|
|
|
|
|
virtual ~ModbusTCPServer() override;
|
|
|
|
|
|
|
|
|
|
|
|
// 实现IYModbusTCPServer接口
|
|
|
|
|
|
// 启动/停止服务器
|
2025-06-08 23:51:48 +08:00
|
|
|
|
virtual int start(int port = 502, int maxConnections = 10) override;
|
2025-06-08 12:48:04 +08:00
|
|
|
|
virtual void stop() override;
|
|
|
|
|
|
bool isRunning() const { return m_isRunning.load(); }
|
|
|
|
|
|
|
|
|
|
|
|
// 设置回调函数
|
|
|
|
|
|
virtual void setWriteCoilsCallback(WriteCoilsCallback callback) override { m_writeCoilsCallback = callback; }
|
|
|
|
|
|
virtual void setWriteRegistersCallback(WriteRegistersCallback callback) override { m_writeRegistersCallback = callback; }
|
2025-06-08 23:51:48 +08:00
|
|
|
|
virtual void setConnectionStatusCallback(ConnectionStatusCallback callback) override { m_connectionStatusCallback = callback; }
|
2025-06-08 12:48:04 +08:00
|
|
|
|
|
|
|
|
|
|
// 数据更新接口 - 线程安全
|
|
|
|
|
|
virtual void updateCoil(uint16_t address, bool value) override;
|
|
|
|
|
|
virtual void updateCoils(uint16_t startAddress, const std::vector<bool>& values) override;
|
|
|
|
|
|
virtual void updateDiscreteInput(uint16_t address, bool value) override;
|
|
|
|
|
|
virtual void updateDiscreteInputs(uint16_t startAddress, const std::vector<bool>& values) override;
|
|
|
|
|
|
virtual void updateHoldingRegister(uint16_t address, uint16_t value) override;
|
|
|
|
|
|
virtual void updateHoldingRegisters(uint16_t startAddress, const std::vector<uint16_t>& values) override;
|
|
|
|
|
|
virtual void updateInputRegister(uint16_t address, uint16_t value) override;
|
|
|
|
|
|
virtual void updateInputRegisters(uint16_t startAddress, const std::vector<uint16_t>& values) override;
|
|
|
|
|
|
|
|
|
|
|
|
// 获取错误信息
|
|
|
|
|
|
std::string getLastError() const;
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
// 服务器主循环
|
|
|
|
|
|
void serverLoop();
|
|
|
|
|
|
|
|
|
|
|
|
// 客户端连接管理
|
|
|
|
|
|
void handleNewConnection();
|
|
|
|
|
|
void handleClientData(std::shared_ptr<ClientConnection> client);
|
|
|
|
|
|
void removeClient(int socket);
|
|
|
|
|
|
void processModbusRequest(std::shared_ptr<ClientConnection> client, const uint8_t* query, int queryLength);
|
|
|
|
|
|
|
|
|
|
|
|
// 数据读取处理器(libmodbus内部调用)
|
|
|
|
|
|
static int readCoilsHandler(modbus_t *ctx, int function_code, int addr, int nb, uint8_t *rsp, int *rsp_length, void *user_data);
|
|
|
|
|
|
static int readDiscreteInputsHandler(modbus_t *ctx, int function_code, int addr, int nb, uint8_t *rsp, int *rsp_length, void *user_data);
|
|
|
|
|
|
static int readHoldingRegistersHandler(modbus_t *ctx, int function_code, int addr, int nb, uint8_t *rsp, int *rsp_length, void *user_data);
|
|
|
|
|
|
static int readInputRegistersHandler(modbus_t *ctx, int function_code, int addr, int nb, uint8_t *rsp, int *rsp_length, void *user_data);
|
|
|
|
|
|
|
|
|
|
|
|
// 数据写入函数(libmodbus内部调用)
|
|
|
|
|
|
static int writeCoilsHandler(modbus_t *ctx, int function_code, int addr, int nb, const uint8_t *req, int req_length, void *user_data);
|
|
|
|
|
|
static int writeRegistersHandler(modbus_t *ctx, int function_code, int addr, int nb, const uint8_t *req, int req_length, void *user_data);
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
// libmodbus context
|
|
|
|
|
|
modbus_t* m_modbusCtx;
|
|
|
|
|
|
modbus_mapping_t* m_mapping;
|
|
|
|
|
|
|
|
|
|
|
|
// 服务器状态
|
|
|
|
|
|
std::atomic<bool> m_isRunning;
|
|
|
|
|
|
std::atomic<bool> m_shouldStop;
|
|
|
|
|
|
std::unique_ptr<std::thread> m_serverThread;
|
|
|
|
|
|
int m_serverSocket;
|
|
|
|
|
|
int m_port;
|
|
|
|
|
|
int m_maxConnections;
|
|
|
|
|
|
|
|
|
|
|
|
// 客户端连接管理
|
|
|
|
|
|
std::unordered_map<int, std::shared_ptr<ClientConnection>> m_clients;
|
|
|
|
|
|
std::mutex m_clientsMutex;
|
|
|
|
|
|
|
|
|
|
|
|
// 数据存储 - 使用libmodbus的mapping结构
|
|
|
|
|
|
std::mutex m_dataMutex;
|
|
|
|
|
|
|
|
|
|
|
|
// 回调函数
|
|
|
|
|
|
WriteCoilsCallback m_writeCoilsCallback;
|
|
|
|
|
|
WriteRegistersCallback m_writeRegistersCallback;
|
2025-06-08 23:51:48 +08:00
|
|
|
|
ConnectionStatusCallback m_connectionStatusCallback;
|
2025-06-08 12:48:04 +08:00
|
|
|
|
|
|
|
|
|
|
// 错误信息
|
|
|
|
|
|
mutable std::mutex m_errorMutex;
|
|
|
|
|
|
std::string m_lastError;
|
|
|
|
|
|
|
|
|
|
|
|
// 设置错误信息
|
|
|
|
|
|
void setLastError(const std::string& error);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-06-08 23:51:48 +08:00
|
|
|
|
#endif // MODBUS_TCP_SERVER_H
|