欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 社会 > Modbus发送的报文何时等到应答

Modbus发送的报文何时等到应答

2024/12/31 0:58:42 来源:https://blog.csdn.net/ACK_ACK/article/details/144303093  浏览:    关键词:Modbus发送的报文何时等到应答

一、Modbus主站如何等待响应报文  

一直以来对于tcp/ip client发送出去的数据,如何等待响应数据,一直是有些疑问的。一种做法是将接收注册为一个回调函数,在回调函数中处理接收到的报文,一般回调函数也是独立的一条线程,此时是异步的;另一种像modbus这种,发送出报文后,等待响应报文。这块就有操作空间了——等待多长时间?如何实现的?通过阅读libModbus库源码——使用select来实现的,抽丝剥茧!

      以modbus_write_bit为例:

//socket send接口    rc = send_msg(ctx, req, req_length);    if (rc > 0) {        /* Used by write_bit and write_register */        uint8_t rsp[MAX_MESSAGE_LENGTH];        rc = _modbus_receive_msg(ctx, rsp, MSG_CONFIRMATION);        if (rc == -1)            return -1;        rc = check_confirmation(ctx, req, rsp, rc);    }

      // _modbus_receive_msg

      接收这块主要使用select判断fd是否可读,当可读时则结合超时时间进行“闭环操作”。结合Modbus Poll的连接参数设置,更加一目了然——连接超时设置,响应时间超时设置,还有一个Delay Between Polls,这个暂不关注。

a48cd7c612f01659b240a40fa89112f2.png

      结合上次连接发送的程序,在此基础上加了带超时的接受调用,接收超时判断具体程序如下:

fd_set rset;   struct timeval tv;   /* Add a file descriptor to the set */   FD_ZERO(&rset);   FD_SET(clientfd, &rset);   // 等待5.5秒   tv.tv_sec = 5;   tv.tv_usec = 500*1000;    // select   int s_rc;   while ((s_rc = select(clientfd + 1, &rset, NULL, NULL, &tv)) == -1) {       if (errno == EINTR) {           if (1) {               fprintf(stderr, "A non blocked signal was caught\n");           }           /* Necessary after an error */           FD_ZERO(&rset);           FD_SET(clientfd, &rset);       } else {            return -1;       }   }

正常接收如下:

4ae8a9daecb3a484b0fe304de59955da.png

接收等待超时如下:

0ea8e94126cbdcbfdd9197ccbc689088.png

二、使用libModbus编写的TCP 从站

      该程序功能是将接收到的线圈值拷贝给离散输入、将接收的保持寄存器值拷贝给输入寄存器。

uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];    int master_socket;    int rc;    fd_set refset;    fd_set rdset;    /* Maximum file descriptor number */    int fdmax;    time_t t_ = time(NULL);    struct tm* stime_ = NULL;    char tmp_[32] = {0};    char *format_time_string[128] = {0};    long long curr_time = 0;    ctx = modbus_new_tcp(MODBUS_SERVER_IP, MODBUS_SERVER_PORT);    //01 Coil  Status  (0x)    //02 Input Status  (1x)    //03 Holding Register  (4x)    //04 Input   Registers (3x)    //TODO!    mb_mapping = modbus_mapping_new(                1024,                1024,                1024,                1024);    if (mb_mapping == NULL) {        cout << "Failed to allocate the mapping:" << modbus_strerror(errno)  << endl;        modbus_free(ctx);    }    server_socket = modbus_tcp_listen(ctx, NB_CONNECTION);    if (server_socket == -1) {        cout << "Unable to listen TCP connection"   << endl;        modbus_free(ctx);    }    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) {            cout << "Server select() failure"   << endl;            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)) {                continue;            }            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) {                    cout << "Server accept() error"   << endl;                } else {                    FD_SET(newfd, &refset);                    if (newfd > fdmax) {                        /* Keep track of the maximum */                        fdmax = newfd;                    }                    stime_=localtime(&t_);                    snprintf(tmp_,sizeof(tmp_),"%04d-%02d-%02d %02d:%02d:%02d",                             1900+stime_->tm_year,1+stime_->tm_mon,stime_->tm_mday, stime_->tm_hour,stime_->tm_min,stime_->tm_sec);                    cout << tmp_ << " New connection from " << inet_ntoa(clientaddr.sin_addr)                         << " " << clientaddr.sin_port                         << " on socket " << newfd << endl;                }            } else {                modbus_set_socket(ctx, master_socket);                rc = modbus_receive(ctx, query);                if(rc > 0){                    // TODO!                    //coil to input                    memcpy(mb_mapping->tab_input_bits, mb_mapping->tab_bits, 256);                    //hold to input                    memcpy(mb_mapping->tab_input_registers, mb_mapping->tab_registers, 256);                    //send frame                    modbus_reply(ctx, query, rc, mb_mapping);                    curr_time = (long long)get_timestamp();                    get_format_time_ms((char *)format_time_string);                    printf("%s Send response frame \n",format_time_string);                }            }        }}

上一篇连接测试:

tcp通信测试报告单1——connect和send

欢迎关注:

如需两个测试工程可留言“Modbus tcp”.

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com