libmodbus TCP切断再接続

10400 ワード

最近プロジェクトでmodbus TCP通信プロトコルが必要で、Qtが持参したmodbusは一対一通信しかできず、1対多にはできないので、開元ライブラリlibmodbusを選択
libmodbusプロトコル紹介中国語完全ブックマーク版:https://download.csdn.net/download/u011251940/11341158
libmodbusソースパッケージをダウンロードします.https://www.libmodbus.org/releases/libmodbus-3.0.6.tar.gz
libmodbusマニュアル:https://libmodbus.org/docs/v3.0.6/
libmodbusデバッグツール:https://download.csdn.net/download/u011251940/11341326
組み込みarmバージョンtar-zxvfのインストール libmodbus-3.0.6.tar.gz cd libmodbus-3.0.6 ./configure --build=i686 --host=arm-cortexa9-linux-gnueabihf --prefix=/opt/libmodbus/install make -j8;make install
一、libmodbus TCP通信demoテストを簡単に書く
#include 
#include 
#include 
#include 
#include 
#include 

#include "modbus/modbus.h"
#include "modbus/modbus-tcp.h"
#include "modbus/modbus-version.h"
//         
const uint16_t UT_BITS_ADDRESS = 0x13;
const uint16_t UT_BITS_NB = 0x25;
const uint8_t UT_BITS_TAB[] = { 0xCD, 0x6B, 0xB2, 0x0E, 0x1B };
//               
const uint16_t UT_INPUT_BITS_ADDRESS = 0xC4;
const uint16_t UT_INPUT_BITS_NB = 0x16;
const uint8_t UT_INPUT_BITS_TAB[] = { 0xAC, 0xDB, 0x35 };
//             
const uint16_t UT_REGISTERS_ADDRESS = 0x6B;
/* Raise a manual exception when this adress is used for the first byte */
const uint16_t UT_REGISTERS_ADDRESS_SPECIAL = 0x6C;
const uint16_t UT_REGISTERS_NB = 0x3;
const uint16_t UT_REGISTERS_TAB[] = { 0x022B, 0x0001, 0x0064 };
/* If the following value is used, a bad response is sent.
   It's better to test with a lower value than
   UT_REGISTERS_NB_POINTS to try to raise a segfault. */
const uint16_t UT_REGISTERS_NB_SPECIAL = 0x2;
//           
const uint16_t UT_INPUT_REGISTERS_ADDRESS = 0x08;
const uint16_t UT_INPUT_REGISTERS_NB = 0x1;
const uint16_t UT_INPUT_REGISTERS_TAB[] = { 0x000A };

int main(int argc, char*argv[])
{
    int socket;
    modbus_t *ctx;
    modbus_mapping_t *mb_mapping;
    int rc;
    int i;
    uint8_t *query;
    int header_length;
    int data;
    int address;

    ctx = modbus_new_tcp("127.0.0.1", 502);
    query = malloc(MODBUS_TCP_MAX_ADU_LENGTH);
    header_length = modbus_get_header_length(ctx);

    modbus_set_debug(ctx, TRUE);
    //new  modbus     
    mb_mapping = modbus_mapping_new(
        UT_BITS_ADDRESS + UT_BITS_NB,//   
        UT_INPUT_BITS_ADDRESS + UT_INPUT_BITS_NB,//      
        UT_REGISTERS_ADDRESS + UT_REGISTERS_NB,//      
        UT_INPUT_REGISTERS_ADDRESS + UT_INPUT_REGISTERS_NB);//      
    if (mb_mapping == NULL)
    {
        fprintf(stderr, "Failed to allocate the mapping: %s
", modbus_strerror(errno)); modbus_free(ctx); return -1; } /** **/ modbus_set_bits_from_bytes(mb_mapping->tab_input_bits,UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB,UT_INPUT_BITS_TAB); /** **/ for (i=0; i < UT_INPUT_REGISTERS_NB; i++) { mb_mapping->tab_input_registers[UT_INPUT_REGISTERS_ADDRESS+i] =UT_INPUT_REGISTERS_TAB[i]; } /** **/ for(i=0; itab_registers[UT_REGISTERS_ADDRESS+i]=UT_REGISTERS_TAB[i]; } socket = modbus_tcp_listen(ctx, 1);// modbus_tcp_accept(ctx, &socket);// for (;;) { // modbus rc = modbus_receive(ctx, query); if (rc == -1) { /* Connection closed by the client or error */ break; } address= (query[header_length+1]<<8) + query[header_length+2];// data=(query[header_length+3]<<8)+query[header_length+4];// /* */ if (query[header_length] == 0x06) { //to do } // modbus rc = modbus_reply(ctx, query, rc, mb_mapping); if (rc == -1) { break; } } printf("Quit the loop: %s
", modbus_strerror(errno)); close(socket); modbus_mapping_free(mb_mapping); free(query); modbus_free(ctx); return 0; }

このコードの実測は基本的にクライアントと通信を接続することができるが、ネットワークを切断して再接続することはできない.
 
二、断網再接続機構部分
#include 
#include 
#include 
#include 
#include 
#include 

#include "modbus.h"
#include "modbus-tcp.h"
#include "modbus-version.h"

#if defined(_WIN32)
#include 
#else
#include 
#include 
#include 
#endif

#define NB_CONNECTION    5

//         
const uint16_t UT_BITS_ADDRESS = 0x13;
const uint16_t UT_BITS_NB = 0x25;
const uint8_t UT_BITS_TAB[] = { 0xCD, 0x6B, 0xB2, 0x0E, 0x1B };
//               
const uint16_t UT_INPUT_BITS_ADDRESS = 0xC4;
const uint16_t UT_INPUT_BITS_NB = 0x16;
const uint8_t UT_INPUT_BITS_TAB[] = { 0xAC, 0xDB, 0x35 };
//             
const uint16_t UT_REGISTERS_ADDRESS = 0x6B;
/* Raise a manual exception when this adress is used for the first byte */
const uint16_t UT_REGISTERS_ADDRESS_SPECIAL = 0x6C;
const uint16_t UT_REGISTERS_NB = 0x3;
const uint16_t UT_REGISTERS_TAB[] = { 0x022B, 0x0001, 0x0064 };
/* If the following value is used, a bad response is sent.
   It's better to test with a lower value than
   UT_REGISTERS_NB_POINTS to try to raise a segfault. */
const uint16_t UT_REGISTERS_NB_SPECIAL = 0x2;
//           
const uint16_t UT_INPUT_REGISTERS_ADDRESS = 0x08;
const uint16_t UT_INPUT_REGISTERS_NB = 0x1;
const uint16_t UT_INPUT_REGISTERS_TAB[] = { 0x000A };

modbus_t *ctx = NULL;
int server_socket;
modbus_mapping_t *mb_mapping;

static void close_sigint(int dummy)
{
    close(server_socket);
    modbus_free(ctx);
    modbus_mapping_free(mb_mapping);

    exit(dummy);
}


int main(void)
{
    int master_socket;
    int rc;
    fd_set refset;
    fd_set rdset;

    /* Maximum file descriptor number */
    int fdmax;

    ctx = modbus_new_tcp("127.0.0.1", 502);

    //new  modbus     
    mb_mapping = modbus_mapping_new(
        UT_BITS_ADDRESS + UT_BITS_NB,//   
        UT_INPUT_BITS_ADDRESS + UT_INPUT_BITS_NB,//      
        UT_REGISTERS_ADDRESS + UT_REGISTERS_NB,//      
        UT_INPUT_REGISTERS_ADDRESS + UT_INPUT_REGISTERS_NB);//      
    if (mb_mapping == NULL)
    {
        fprintf(stderr, "Failed to allocate the mapping: %s
", modbus_strerror(errno)); modbus_free(ctx); return -1; } /** **/ modbus_set_bits_from_bytes(mb_mapping->tab_input_bits,UT_INPUT_BITS_ADDRESS, UT_INPUT_BITS_NB,UT_INPUT_BITS_TAB); /** **/ for (i=0; i < UT_INPUT_REGISTERS_NB; i++) { mb_mapping->tab_input_registers[UT_INPUT_REGISTERS_ADDRESS+i] =UT_INPUT_REGISTERS_TAB[i]; } /** **/ for(i=0; itab_registers[UT_REGISTERS_ADDRESS+i]=UT_REGISTERS_TAB[i]; } server_socket = modbus_tcp_listen(ctx, NB_CONNECTION); signal(SIGINT, close_sigint); /* Clear the reference set of socket */ FD_ZERO(&refset); /* Add the server socket */ FD_SET(server_socket, &refset); /* Keep track of the max file descriptor */ fdmax = server_socket; for (;;) { rdset = refset; if (select(fdmax+1, &rdset, NULL, NULL, NULL) == -1) { perror("Server select() failure."); close_sigint(1); } /* Run through the existing connections looking for data to be * read */ for (master_socket = 0; master_socket <= fdmax; master_socket++) { if (FD_ISSET(master_socket, &rdset)) { if (master_socket == server_socket) { /* A client is asking a new connection */ socklen_t addrlen; struct sockaddr_in clientaddr; int newfd; /* Handle new connections */ addrlen = sizeof(clientaddr); memset(&clientaddr, 0, sizeof(clientaddr)); newfd = accept(server_socket, (struct sockaddr *)&clientaddr, &addrlen); if (newfd == -1) { perror("Server accept() error"); } else { FD_SET(newfd, &refset); if (newfd > fdmax) { /* Keep track of the maximum */ fdmax = newfd; } printf("New connection from %s:%d on socket %d
", inet_ntoa(clientaddr.sin_addr), clientaddr.sin_port, newfd); } } else { /* An already connected master has sent a new query */ uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH]; int data = 0; int address=0; modbus_set_socket(ctx, master_socket); rc = modbus_receive(ctx, query); address = (query[header_length+1]<<8) + query[header_length+2]; if(query[header_length] == 0x06 ) { //to do } if (rc != -1) { modbus_reply(ctx, query, rc, mb_mapping); } else { /* Connection closed by the client, end of server */ printf("Connection closed on socket %d
", master_socket); close(master_socket); /* Remove from reference set */ FD_CLR(master_socket, &refset); if (master_socket == fdmax) { fdmax--; } } } } } } return 0; }

断網再接続メカニズムの実測が有効である