"# \u5b9e\u73b0\u5de5\u4e1a\u7ea7Modbus TCP\u670d\u52a1\u5668\uff1a\u4f7f\u7528C\u8bed\u8a00\u548clibmodbus\u7684\u5b9e\u8df5\u6559\u7a0b\n\n> 2024-04-21 | 2024-04-21\n> https:\/\/www.modbus.cn\/en\/27705.html\n\n**Modbus\u7f16\u7a0b\u5f00\u53d1**\n\n---\n\n\u5728\u5de5\u4e1a\u81ea\u52a8\u5316\u9886\u57df\uff0cModbus\u534f\u8bae\u56e0\u5176\u7b80\u6d01\u6027\u548c\u5e7f\u6cdb\u652f\u6301\u800c\u5e38\u88ab\u7528\u4e8e\u8bbe\u5907\u95f4\u901a\u4fe1\u3002\u672c\u6587\u4ecb\u7ecd\u5982\u4f55\u4f7f\u7528C\u8bed\u8a00\u548clibmodbus\u5e93\u6765\u521b\u5efa\u4e00\u4e2a\u529f\u80fd\u9f50\u5168\u7684Modbus TCP\u670d\u52a1\u5668\uff0c\u5b9e\u73b0\u8bbe\u5907\u95f4\u7684\u6709\u6548\u901a\u4fe1\u3002\n\n\u5b8c\u6574\u4ee3\u7801\uff1a\n\n```\n#include &lt;errno.h>\n#include &lt;signal.h>\n#include &lt;stdio.h>\n#include &lt;stdlib.h>\n#include &lt;string.h>\n#include &lt;unistd.h>\n\n#include &lt;modbus.h>\n\n#if defined(_WIN32)\n#include &lt;ws2tcpip.h>\n#else\n#include &lt;arpa\/inet.h>\n#include &lt;netinet\/in.h>\n#include &lt;sys\/select.h>\n#include &lt;sys\/socket.h>\n#endif\n\n#define NB_CONNECTION 5 \/\/ \u6700\u5927\u8fde\u63a5\u6570\u5b9a\u4e49\u4e3a5\n\nstatic modbus_t *ctx = NULL;  \/\/ Modbus\u4e0a\u4e0b\u6587\nstatic modbus_mapping_t *mb_mapping;  \/\/ Modbus\u6620\u5c04\n\nstatic int server_socket = -1;  \/\/ \u670d\u52a1\u5668socket\n\n\/\/ SIGINT\u4fe1\u53f7\u5904\u7406\u51fd\u6570\uff0c\u7528\u4e8e\u6e05\u7406\u8d44\u6e90\nstatic void close_sigint(int dummy)\n{\n    if (server_socket != -1) {\n        close(server_socket);  \/\/ \u5173\u95ed\u670d\u52a1\u5668socket\n    }\n    modbus_free(ctx);  \/\/ \u91ca\u653eModbus\u4e0a\u4e0b\u6587\n    modbus_mapping_free(mb_mapping);  \/\/ \u91ca\u653eModbus\u6620\u5c04\u8d44\u6e90\n\n    exit(dummy);  \/\/ \u9000\u51fa\u7a0b\u5e8f\n}\n\nint main(void)\n{\n    uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];  \/\/ \u5b58\u50a8Modbus\u67e5\u8be2\u7684\u6570\u7ec4\n    int master_socket;\n    int rc;\n    fd_set refset;  \/\/ \u53c2\u8003\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26\u96c6\u5408\n    fd_set rdset;  \/\/ \u7528\u4e8eselect\u8c03\u7528\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26\u96c6\u5408\n    int fdmax;  \/\/ \u6700\u5927\u7684\u6587\u4ef6\u63cf\u8ff0\u7b26\u53f7\n\n    ctx = modbus_new_tcp(\"127.0.0.1\", 1502);  \/\/ \u521b\u5efa\u4e00\u4e2a\u65b0\u7684TCP Modbus\u4e0a\u4e0b\u6587\n\n    mb_mapping = modbus_mapping_new(MODBUS_MAX_READ_BITS, 0, MODBUS_MAX_READ_REGISTERS, 0);\n    if (mb_mapping == NULL) {\n        fprintf(stderr, \"Failed to allocate the mapping: %s\\n\", modbus_strerror(errno));\n        modbus_free(ctx);\n        return -1;\n    }\n\n    server_socket = modbus_tcp_listen(ctx, NB_CONNECTION);  \/\/ \u76d1\u542cTCP\u8fde\u63a5\n    if (server_socket == -1) {\n        fprintf(stderr, \"Unable to listen TCP connection\\n\");\n        modbus_free(ctx);\n        return -1;\n    }\n\n    signal(SIGINT, close_sigint);  \/\/ \u6ce8\u518cSIGINT\u4fe1\u53f7\u5904\u7406\u51fd\u6570\n\n    FD_ZERO(&amp;refset);  \/\/ \u6e05\u7a7a\u53c2\u8003\u96c6\n    FD_SET(server_socket, &amp;refset);  \/\/ \u5c06\u670d\u52a1\u5668socket\u52a0\u5165\u53c2\u8003\u96c6\n\n    fdmax = server_socket;  \/\/ \u521d\u59cb\u5316\u6700\u5927\u6587\u4ef6\u63cf\u8ff0\u7b26\u53f7\n\n    for (;;) {\n        rdset = refset;\n        if (select(fdmax + 1, &amp;rdset, NULL, NULL, NULL) == -1) {\n            perror(\"Server select() failure.\");\n            close_sigint(1);\n        }\n\n        for (master_socket = 0; master_socket &lt;= fdmax; master_socket++) {\n            if (!FD_ISSET(master_socket, &amp;rdset)) {\n                continue;\n            }\n\n            if (master_socket == server_socket) {\n                socklen_t addrlen;\n                struct sockaddr_in clientaddr;\n                int newfd;\n\n                addrlen = sizeof(clientaddr);\n                memset(&amp;clientaddr, 0, sizeof(clientaddr));\n                newfd = accept(server_socket, (struct sockaddr *)&amp;clientaddr, &amp;addrlen);\n                if (newfd == -1) {\n                    perror(\"Server accept() error\");\n                } else {\n                    FD_SET(newfd, &amp;refset);\n\n                    if (newfd > fdmax) {\n                        fdmax = newfd;\n                    }\n                    printf(\"New connection from %s:%d on socket %d\\n\",\n                           inet_ntoa(clientaddr.sin_addr),\n                           ntohs(clientaddr.sin_port),\n                           newfd);\n                }\n            } else {\n                modbus_set_socket(ctx, master_socket);\n                rc = modbus_receive(ctx, query);\n                if (rc > 0) {\n                    modbus_reply(ctx, query, rc, mb_mapping);\n                } else if (rc == -1) {\n                    printf(\"Connection closed on socket %d\\n\", master_socket);\n                    close(master_socket);\n                    FD_CLR(master_socket, &amp;refset);\n\n                    if (master_socket == fdmax) {\n                        fdmax--;\n                    }\n                }\n            }\n        }\n    }\n\n    return 0;\n}\n\n```\n\n#### 1. \u521d\u59cb\u5316Modbus\u670d\u52a1\u5668\n\n\u9996\u5148\uff0c\u9700\u8981\u521b\u5efa\u4e00\u4e2aModbus TCP\u670d\u52a1\u5668\u5b9e\u4f8b\u3002\u4f7f\u7528`modbus_new_tcp`\u51fd\u6570\u521d\u59cb\u5316\u4e00\u4e2a\u6307\u5411`modbus_t`\u7c7b\u578b\u7684\u6307\u9488\uff0c\u8fd9\u4e2a\u51fd\u6570\u7684\u53c2\u6570\u662f\u670d\u52a1\u5668\u7684IP\u5730\u5740\u548c\u7aef\u53e3\u53f7\u3002\u5728\u672c\u4f8b\u4e2d\uff0c\u670d\u52a1\u5668\u914d\u7f6e\u4e3a\u76d1\u542c\u672c\u5730\u5730\u5740127.0.0.1\u4e0a\u76841502\u7aef\u53e3\uff1a\n\n```\nctx = modbus_new_tcp(&quot;127.0.0.1&quot;, 1502);\n```\n\n#### 2. \u8bbe\u7f6eModbus\u6620\u5c04\n\nModbus\u6620\u5c04\u662f\u670d\u52a1\u5668\u5b58\u50a8\u5176\u6570\u636e\uff08\u6bd4\u5982\u7ebf\u5708\u3001\u79bb\u6563\u8f93\u5165\u3001\u4fdd\u6301\u5bc4\u5b58\u5668\u548c\u8f93\u5165\u5bc4\u5b58\u5668\uff09\u7684\u65b9\u5f0f\u3002\u4f7f\u7528`modbus_mapping_new`\u6765\u5206\u914d\u5e76\u521d\u59cb\u5316\u8fd9\u4e9b\u6570\u636e\u533a\uff1a\n\n```\nmb_mapping = modbus_mapping_new(MODBUS_MAX_READ_BITS, 0, MODBUS_MAX_READ_REGISTERS, 0);\n```\n\n\u5982\u679c\u6620\u5c04\u521b\u5efa\u5931\u8d25\uff0c\u670d\u52a1\u5668\u5c06\u6253\u5370\u9519\u8bef\u6d88\u606f\u5e76\u9000\u51fa\u3002\n\n#### 3. \u76d1\u542c\u8fde\u63a5\n\n\u4f7f\u7528`modbus_tcp_listen`\u51fd\u6570\u6765\u76d1\u542c\u7f51\u7edc\u8fde\u63a5\uff0c\u5b83\u8fd4\u56de\u4e00\u4e2asocket\u63cf\u8ff0\u7b26\u3002\u670d\u52a1\u5668\u80fd\u591f\u5904\u7406\u7684\u6700\u5927\u8fde\u63a5\u6570\u7531`NB_CONNECTION`\u5b8f\u5b9a\u4e49\uff1a\n\n```\nserver_socket = modbus_tcp_listen(ctx, NB_CONNECTION);\n```\n\n#### 4. \u5904\u7406SIGINT\u4fe1\u53f7\n\n\u4e3a\u4e86\u80fd\u591f\u4f18\u96c5\u5730\u5173\u95ed\u670d\u52a1\u5668\u5e76\u91ca\u653e\u8d44\u6e90\uff0c\u6211\u4eec\u4f7f\u7528`signal`\u51fd\u6570\u6765\u6355\u83b7SIGINT\u4fe1\u53f7\uff08\u901a\u5e38\u7531Ctrl+C\u5f15\u53d1\uff09\uff0c\u5e76\u5c06\u5176\u5173\u8054\u5230`close_sigint`\u51fd\u6570\uff1a\n\n```\nsignal(SIGINT, close_sigint);\n```\n\n`close_sigint`\u51fd\u6570\u5173\u95edsocket\uff0c\u91ca\u653eModbus\u4e0a\u4e0b\u6587\u548c\u6620\u5c04\uff0c\u7136\u540e\u9000\u51fa\u7a0b\u5e8f\u3002\n\n#### 5. \u4e3b\u5faa\u73af\n\n\u670d\u52a1\u5668\u8fd0\u884c\u5728\u4e00\u4e2a\u65e0\u9650\u5faa\u73af\u4e2d\uff0c\u4f7f\u7528`select`\u51fd\u6570\u6765\u76d1\u542csocket\u4e0a\u7684\u6d3b\u52a8\u3002\u5982\u679c`select`\u68c0\u6d4b\u5230\u6d3b\u52a8\uff0c\u670d\u52a1\u5668\u5c06\u68c0\u67e5\u662f\u65b0\u7684\u8fde\u63a5\u8bf7\u6c42\u8fd8\u662f\u5df2\u5efa\u7acb\u8fde\u63a5\u7684\u6570\u636e\u8bf7\u6c42\uff1a\n\n```\nif (master_socket == server_socket) {\n    \/\/ \u5904\u7406\u65b0\u7684\u8fde\u63a5\u8bf7\u6c42\n} else {\n    \/\/ \u5904\u7406\u6765\u81ea\u5df2\u8fde\u63a5\u5ba2\u6237\u7aef\u7684\u6570\u636e\n}\n```\n\n\u5bf9\u4e8e\u65b0\u7684\u8fde\u63a5\uff0c\u670d\u52a1\u5668\u63a5\u53d7\u8fde\u63a5\u5e76\u5c06\u65b0socket\u6dfb\u52a0\u5230\u76d1\u542c\u96c6\u5408\u4e2d\u3002\u5bf9\u4e8e\u6570\u636e\u8bf7\u6c42\uff0c\u670d\u52a1\u5668\u4f7f\u7528`modbus_receive`\u63a5\u6536\u6570\u636e\uff0c\u7136\u540e\u4f7f\u7528`modbus_reply`\u53d1\u9001\u54cd\u5e94\u3002\n\n#### 6. \u6027\u80fd\u8bc4\u4f30\n\n\u4e3a\u4e86\u8bc4\u4f30\u670d\u52a1\u5668\u7684\u6027\u80fd\uff0c\u4ee3\u7801\u4e2d\u52a0\u5165\u4e86\u5bf9\u4f20\u8f93\u6570\u636e\u901f\u7387\u7684\u8ba1\u7b97\u3002\u670d\u52a1\u5668\u8ba1\u7b97\u5728\u7ed9\u5b9a\u65f6\u95f4\u5185\u6210\u529f\u5904\u7406\u7684\u4f4d\uff08bits\uff09\u548c\u5bc4\u5b58\u5668\uff08registers\uff09\u7684\u6570\u91cf\uff0c\u4ece\u800c\u5f97\u5230\u70b9\/\u79d2\u548cKiB\/\u79d2\u7684\u4f20\u8f93\u901f\u7387\uff1a\n\n```\nrate = (n_loop * nb_points) * G_MSEC_PER_SEC \/ (end - start);\nprintf(&quot;* %d points\/s\\n&quot;, rate);\n```\n\n\u8fd9\u4e9b\u6027\u80fd\u6307\u6807\u5bf9\u4e8e\u4f18\u5316\u670d\u52a1\u5668\u8bbe\u7f6e\u548c\u7f51\u7edc\u914d\u7f6e\u975e\u5e38\u6709\u7528\u3002\n\n#### \u7ed3\u8bba\n\n\u901a\u8fc7C\u8bed\u8a00\u548clibmodbus\u5e93\uff0c\u53ef\u4ee5\u6709\u6548\u5730\u5b9e\u73b0\u4e00\u4e2aModbus TCP\u670d\u52a1\u5668\uff0c\u5b83\u4e0d\u4ec5\u652f\u6301\u591a\u5ba2\u6237\u7aef\u8fde\u63a5\uff0c\u8fd8\u80fd\u591f\u63d0\u4f9b\u5173\u4e8e\u5176\u6027\u80fd\u7684\u5b9e\u65f6\u6570\u636e\u3002\u8fd9\u4e3a\u5de5\u4e1a\u5e94\u7528\u4e2d\u7684\u8bbe\u5907\u901a\u4fe1\u63d0\u4f9b\u4e86\u4e00\u4e2a\u5f3a\u5927\u4e14\u7075\u6d3b\u7684\u89e3\u51b3\u65b9\u6848\u3002\n\n---\n*modbus.cn*\n"