写了一个modbus服务器,支持多连接

#include "RDSModbusSlave.h"
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @date       2022/01/17
 **************************************************************/
RDSModbusSlave::RDSModbusSlave() :_port(DEFAULT_PORT)
{
    if (initModbus() == true) {
    }
    else {
        throw exception();
    }
    memset(coil, 0, sizeof(coil));
    memset(input_Coil, 0, sizeof(input_Coil));
    memset(hold_Register, 0, sizeof(hold_Register));
    memset(input_Register, 0, sizeof(input_Register));
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @return     int
 * @date       2022/01/17
 **************************************************************/
int RDSModbusSlave::recvMsg(int socketId, uint8_t* buffer)
{
    return recv(socketId, (char*)buffer, MODBUS_TCP_MAX_ADU_LENGTH, 0);
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @return     int
 * @date       2022/01/17
 **************************************************************/
int RDSModbusSlave::sendMsg(int socketId, uint8_t slaverId, uint16_t msg_Id, uint16_t amount,
    void* value, uint16_t address, int funCode)
{
    int ret = 0;
    uint16_t* Rvalue = (uint16_t*)value;
    bool* Bvalue = (bool*)value;
    uint8_t* to_send = nullptr;
    /*write single Registers/write manyRegisters/write single coil/write many coil*/
    if (funCode == WRITE_REG || funCode == WRITE_REGS || funCode == WRITE_COIL || funCode == WRITE_COILS) {
        to_send = new uint8_t[12];
        to_send[0] = static_cast<uint8_t>(msg_Id >> 8u);
        to_send[1] = static_cast<uint8_t>(msg_Id & 0x00FFu);
        to_send[2] = 0;
        to_send[3] = 0;
        to_send[4] = 0;
        to_send[5] = (uint8_t)(6);
        to_send[6] = static_cast<uint8_t>(slaverId);
        to_send[7] = static_cast<uint8_t>(funCode);
        to_send[8] = static_cast<uint8_t>(address >> 8u);
        to_send[9] = static_cast<uint8_t>(address & 0x00FFu);
        to_send[10] = static_cast<uint8_t>(amount >> 8u);
        to_send[11] = static_cast<uint8_t>(amount & 0x00FFu);
        ret = send(socketId, (const char*)to_send, ((size_t)(12)), 0);
    }
    /*read inputRegister/read holdRegister*/
    else if (funCode == READ_REGS || funCode == READ_INPUT_REGS) {
        to_send = new uint8_t[9 + 2 * amount];
        to_send[0] = static_cast<uint8_t>(msg_Id >> 8u);
        to_send[1] = static_cast<uint8_t>(msg_Id & 0x00FFu);
        to_send[2] = 0;
        to_send[3] = 0;
        to_send[4] = 0;
        to_send[5] = (uint8_t)(3 + 2 * amount);
        to_send[6] = static_cast<uint8_t>(slaverId);
        to_send[7] = static_cast<uint8_t>(funCode);
        to_send[8] = static_cast<uint8_t>(2 * amount);
        for (int i = 0; i < amount; i++) {
            to_send[9 + 2 * i] = static_cast<uint8_t>(Rvalue[i] >> 8u);
            to_send[10 + 2 * i] = static_cast<uint8_t>(Rvalue[i] & 0x00FFu);
        }
        ret = send(socketId, (const char*)to_send, ((size_t)(9 + 2 * amount)), 0);
    }
    /*read coil/read inputCoil*/
    else if (funCode == READ_COILS || funCode == READ_INPUT_BITS) {
        /*bit/8*/
        to_send = new uint8_t[8 + ((amount - 1) / 8) + 2];
        to_send[0] = static_cast<uint8_t>(msg_Id >> 8u);
        to_send[1] = static_cast<uint8_t>(msg_Id & 0x00FFu);
        to_send[2] = 0;
        to_send[3] = 0;
        to_send[4] = 0;
        to_send[5] = static_cast<uint8_t>(2 + 1 + (((amount - 1) / 8) + 1));
        to_send[6] = static_cast<uint8_t>(slaverId);
        to_send[7] = static_cast<uint8_t>(funCode);
        to_send[8] = static_cast<uint8_t>(((amount - 1) / 8) + 1);
        /*init*/
        for (int i = 0; i < (((amount - 1) / 8) + 1); i++) {
            to_send[9 + i] = 0;
        }
        /*reply value*/
        for (int i = 0; i < amount; i++) {
            to_send[9 + i / 8] += static_cast<uint8_t>(Bvalue[i] << (i % 8u));
        }
        ret = send(socketId, (const char*)to_send, (size_t)(8 + ((amount - 1) / 8) + 2), 0);
    }
    delete[] to_send;
    return ret;
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @date       2022/01/17
 **************************************************************/
void RDSModbusSlave::printInfo(uint8_t* query)
{
    msg_Id = uint16_t((query[0] << 8) | query[1]);
    slaverId = uint16_t(((uint8_t)0 << 8) | query[6]);
    funCode = (uint16_t(((uint8_t)0 << 8) | query[7]));
    startAddress = (uint16_t((query[8] << 8) | query[9]));
    amount = (uint16_t((query[10] << 8) | query[11]));
    registerEnd = startAddress + amount;
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @date       2022/01/17
 **************************************************************/
bool RDSModbusSlave::setCoil(uint16_t index, bool value)
{
    if (index < MODBUSREGISTERSNUMBER) {
        coil[index] = value;
        return true;
    }
    else {
        return false;
    }
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @date       2022/01/17
 **************************************************************/
bool RDSModbusSlave::setHoldRegisters(uint16_t index, uint16_t value)
{
    if (index < MODBUSREGISTERSNUMBER) {
        hold_Register[index] = value;
        return true;
    }
    else {
        return false;
    }
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @return     bool
 * @date       2022/01/17
 **************************************************************/
bool RDSModbusSlave::initModbus()
{
    int ret;
#ifdef _WIN32
    if ((ret = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) {
        return false;
    }
#endif
    _socket = socket(AF_INET, SOCK_STREAM, 0);
    if (!X_ISVALIDSOCKET(_socket)) {
#ifdef _WIN32
        WSACleanup();
#endif
        return false;
    }
    memset(&_server, 0, sizeof(_server));
    _server.sin_family = AF_INET;
    _server.sin_addr.s_addr = htonl(INADDR_ANY);
    _server.sin_port = htons(_port);
    if((ret = ::bind(_socket, (SOCKADDR*)&_server, sizeof(SOCKADDR))) != 0) {
#ifdef _WIN32
        WSACleanup();
#endif
        return false;
    }
    if ((ret = listen(_socket, 10)) != 0) {
#ifdef _WIN32
        WSACleanup();
#endif
        return false;
    }
    return true;
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @brief      run
 * @date       2022/01/18
 **************************************************************/
void RDSModbusSlave::run()
{
    LogInfo(" RDSModbusSlave::run()");
    while (true) {
        recieveMessages();
    }
    return;
}
/***************************************************************
 * @file       RDSModbusSlave.cpp
 * @author     seer-txj
 * @date       2022/01/18
 **************************************************************/
void RDSModbusSlave::recieveMessages()
{
    uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
    int len = sizeof(SOCKADDR);
    int fd_num = 0, fd_max = 0, ret = 0, i = 0, clnt_sock = -1;
    fd_set reads, cpy_reads;
    FD_ZERO(&reads);
    FD_SET(_socket, &reads);
    fd_max = _socket;
    while (true) {
        cpy_reads = reads;
        if ((fd_num = select(fd_max + 1, &cpy_reads, NULL, NULL, NULL)) == -1) {
            break;
        }
        if (fd_num == 0) {
            continue;
        }
        for (i = 0; i < fd_max + 1; i++) {
            if (FD_ISSET(i, &cpy_reads)) {
                if (i == _socket) {
                    clnt_sock = accept(_socket, (SOCKADDR*)&_client, &len);
                    if (clnt_sock == -1) {
                        continue;
                    }
                    FD_SET(clnt_sock, &reads);
                    if (fd_max < clnt_sock)
                        fd_max = clnt_sock;
                }
                else {
                    memset(query, 0, MODBUS_TCP_MAX_ADU_LENGTH);
                    int x = 11, y = 12;
                    ret = recvMsg(i, query);
                    if ((ret == 0) || (ret == -1)) {
                        FD_CLR(i, &reads);
                        X_CLOSE_SOCKET(i);
                        continue;
                    }
                    else if(ret > 0){
                        printInfo(query);
                        switch (funCode) {
                        case READ_COILS:
                            if (sendMsg(i, slaverId, msg_Id, amount, coil + startAddress, startAddress, funCode) != -1) {
                            }
                            break;
                        case READ_INPUT_BITS:
                            if (sendMsg(i, slaverId, msg_Id, amount, input_Coil + startAddress, startAddress, funCode) != -1) {
                            }
                            break;
                        case READ_REGS:
                            updateAreaStatus();
                            if (sendMsg(i, slaverId, msg_Id, amount, hold_Register + startAddress, startAddress, funCode) != -1) {
                            }
                            break;
                        case READ_INPUT_REGS:
                            if (sendMsg(i, slaverId, msg_Id, amount, input_Register + startAddress, startAddress, funCode) != -1) {
                            }
                            break;
                        case WRITE_COIL:
                            if (amount != 0) {
                                if (setCoil(startAddress, 1) != false) {                                
                                }
                            }
                            else {
                                if (setCoil(startAddress, 0) != false) {
                                }
                            }
                            if (sendMsg(i, slaverId, msg_Id, amount, nullptr, startAddress, funCode) != -1) {
                            }
                            break;
                        case WRITE_REG:
                            setHoldRegisters(startAddress, amount);
                            if (sendMsg(i, slaverId, msg_Id, amount, nullptr, startAddress, funCode) != -1) {
                            }
                            break;
                        case WRITE_COILS:
                            {
                                int k = 0, z = 0;
                                for (int index = startAddress; index < (startAddress + amount); index++) {
                                    if (k == 8) {
                                        k = 0;
                                        z++;
                                    }
                                    if (setCoil(index, (((uint16_t(((uint8_t)0 << 8) | query[13 + z])) >> (k++)) & 1)) != false) {                                      
                                    }
                                }
                                if (sendMsg(i, slaverId, msg_Id, amount, nullptr, startAddress, funCode) != -1) {
                                }
                                break;
                            }
                        case WRITE_REGS:
                            for (int index = startAddress; index < (startAddress + amount); index++) {
                                x += 2;
                                y += 2;
                                if (setHoldRegisters(index, uint16_t((query[x] << 8) | query[y])) != false) {
                                }
                            }
                            if (sendMsg(i, slaverId, msg_Id, amount, nullptr, startAddress, funCode) != -1) {
                            }                           setAreaStatus(startAddress, amount);
                            break;
                        default:
                        }
                    }
                }
            }
        }
    }
}
#ifndef RDSMODBUSSLAVE_H
#define RDSMODBUSSLAVE_H
#include <iostream>
#include <mutex>
#include <sstream>
#include <stdlib.h>
#include <string>
#include <thread>
using namespace std;
using namespace rbk;
#define DEFAULT_PORT 502
#define MODBUSREGISTERSNUMBER 500
#define MODBUS_TCP_MAX_ADU_LENGTH 260
#define READ_COILS 0x01
#define READ_INPUT_BITS 0x02
#define READ_REGS 0x03 
#define READ_INPUT_REGS 0x04
#define WRITE_COIL 0x05
#define WRITE_REG 0x06
#define WRITE_COILS 0x0F
#define WRITE_REGS 0x10
#ifdef _WIN32
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#pragma comment(lib, "Ws2_32.lib")
using X_SOCKET = SOCKET;
using ssize_t = int;
#define X_ISVALIDSOCKET(s) ((s) != INVALID_SOCKET)
#define X_CLOSE_SOCKET(s) closesocket(s)
#define X_ISCONNECTSUCCEED(s) ((s) != SOCKET_ERROR)
#else
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
using X_SOCKET = int;
#define X_ISVALIDSOCKET(s) ((s) >= 0)
#define X_CLOSE_SOCKET(s) close(s)
#define X_ISCONNECTSUCCEED(s) ((s) >= 0)
#endif
using SOCKADDR = struct sockaddr;
using SOCKADDR_IN = struct sockaddr_in;
class RDSModbusSlave {
public:
    RDSModbusSlave();
    ~RDSModbusSlave() = default;
    void run();
public:
    bool initModbus();
    void recieveMessages();
    void printInfo(uint8_t* query);
    bool setCoil(uint16_t index, bool value);
    int recvMsg(int socketId, uint8_t* buffer);
    bool setHoldRegisters(uint16_t index, uint16_t value);
    int sendMsg(int socketId, uint8_t slaverId, uint16_t msg_Id, uint16_t amount,
        void* value, uint16_t address, int funCode);
private:
    int msg_Id{};
    int amount{};
    int funCode{};
    int slaverId{};
    int startAddress{};
    int registerEnd{};
#ifdef _WIN32
    WSADATA wsaData;
#endif
    uint32_t _port{};
    X_SOCKET _socket{};
    SOCKADDR_IN _server{}, _client{};
    bool coil[MODBUSREGISTERSNUMBER];
    bool input_Coil[MODBUSREGISTERSNUMBER];
    uint16_t hold_Register[MODBUSREGISTERSNUMBER];
    uint16_t input_Register[MODBUSREGISTERSNUMBER];
};
#endif // RDSMODBUSSLAVE_H
/*
0x:线圈
1x:离散量(只读)
3x:输入寄存器
4x:保持寄存器(读写)
*/
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值