有了网站模板 还要怎样做,自己建网站做网店,一般使用的分辨率的显示密度是多少,海口 网站开发初级代码游戏的专栏介绍与文章目录-CSDN博客
我的github#xff1a;codetoys#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C的#xff0c;可以在任何平台上使用。
源码指引#xff1a;github源…初级代码游戏的专栏介绍与文章目录-CSDN博客
我的githubcodetoys所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C的可以在任何平台上使用。
源码指引github源码指引_初级代码游戏的博客-CSDN博客 libmodbus很好用不过多是写客户端。为了测试客户端一般会用物理设备或模拟程序不过既然libmodbus支持写服务端为什么不直接写一个服务端用来测试呢串口当然可能受数量限制TCP就没有任何限制了
目录
一、主要过程
1.1 创建上下文对象设定参数
1.1.1 坑Ubuntu上无法打开低端口
1.2 数据映射
1.3 启动服务
1.4 接受连接
1.5 接收请求
1.6 返回应答
1.7 清理
二、完整代码
三、处理多个连接 一、主要过程
1.1 创建上下文对象设定参数 MODBUS_API modbus_t* modbus_new_tcp(const char *ip_address, int port);非常简单指定地址端口就可以了。地址NULL则使用任何地址标准端口是502。
1.1.1 坑Ubuntu上无法打开低端口 这个坑好大我试了好久程序都不正确在后面modbus_receive的时候挂了开始以为是内存错误后来老老实实每步检查返回值才发现是modbus_tcp_listen这一步就失败了提示“无权操作”用了su也不行于是想到会不会是低端口保护改成高端口就正常了比如10502。 低端口0-1023由国际组织分配Ubuntu限制应用程序不能使用是可以理解的。
1.2 数据映射
typedef struct _modbus_mapping_t {int nb_bits;int start_bits;int nb_input_bits;int start_input_bits;int nb_input_registers;int start_input_registers;int nb_registers;int start_registers;uint8_t *tab_bits;uint8_t *tab_input_bits;uint16_t *tab_input_registers;uint16_t *tab_registers;
} modbus_mapping_t;MODBUS_API modbus_mapping_t* modbus_mapping_new(int nb_bits, int nb_input_bits,int nb_registers, int nb_input_registers);根据给定的四种数据的数量创建存储结构返回的结构里面对每种数据都包含三个值
数据个数最大数据量起始modbus地址数据对应的modbus地址可以不从0开始比如只提供【100-120】数据指针存储实际数据可以根据需要直接修改每个数据的值但是不要动这个指针这是内部创建的用另一个函数释放
1.3 启动服务
MODBUS_API int modbus_tcp_listen(modbus_t *ctx, int nb_connection);这会根据之前设置的参数来启动服务nb_connection是一般TCP编程里面的等待连接队列长度。 返回值是服务socket的值如果成功返回值应该大于0。服务端口要自行用close来关闭。
1.4 接受连接
MODBUS_API int modbus_tcp_accept(modbus_t *ctx, int *s);这一步的参数s就是前一步的返回值也就是服务socket。 返回值是新socket同时新socket也会存储在上下文中后续收发操作使用上下文中存储的socket。
1.5 接收请求
MODBUS_API int modbus_receive(modbus_t *ctx, uint8_t *req);这个函数接收一个请求并存储在req里面返回值是数据长度
大于0 有效的请求等于0 忽略的请求比如从站号不匹配本例程并未设置从站号-1 出错 循环调用此函数接受请求并可以在接收之后进行一些处理然后再发送应答。
1.6 返回应答
MODBUS_API int modbus_reply(modbus_t *ctx, const uint8_t *req,int req_length, modbus_mapping_t *mb_mapping);如果没什么别的要求直接调用这个函数返回应答就可以了。调用之前可以修改数据映射的数据。
1.7 清理 if (s ! -1){close(s);}modbus_mapping_free(mb_mapping);modbus_close(ctx);modbus_free(ctx);服务端口需要关闭数据映射和上下文需要释放。
二、完整代码 modbus_t * ctx modbus_new_tcp(NULL, 10503);//ubuntu上开启低端口会报权限不足su也不行modbus_mapping_t * mb_mapping modbus_mapping_new(100, 100, 100, 100);if (mb_mapping NULL){fprintf(stderr, Failed to allocate the mapping: %s\n, modbus_strerror(errno));modbus_free(ctx);return -1;}//设置初值{mb_mapping-start_registers 0;for (int i 0; i 10; i){mb_mapping-tab_registers[mb_mapping-start_registers i] i;}}while (CMyProcess::isProcessLive(parent_pid)){int s modbus_tcp_listen(ctx, 5);if (s 0){thelog modbus_tcp_listen error : modbus_strerror(errno) endi;SleepSeconds(1);continue;}modbus_tcp_accept(ctx, s); thelog s: s endi;while (CMyProcess::isProcessLive(parent_pid)){uint8_t query[512];int rc modbus_receive(ctx, query);if (rc 0){modbus_reply(ctx, query, rc, mb_mapping);}else if (rc -1){break;}//改变数据for (int i 0; i 10; i){mb_mapping-tab_registers[mb_mapping-start_registers i];}}thelog 对方断开或出错 modbus_strerror(errno) endi;if (s ! -1){close(s);}}modbus_mapping_free(mb_mapping);modbus_close(ctx);modbus_free(ctx);CMyProcess::isProcessLive(parent_pid)判断父进程是否存在换成死循环就可以了。 专门对保持寄存器的前十个值做了设置因为测试只用了这几个值。 一次只能处理一个连接这个连接断开才会处理下一个连接。因为客户socket是存储在上下文的所以并行处理多个连接不方便。实际上写这个代码的目的是程序连接到自身来进行回归测试的。
三、处理多个连接 额外有个函数modbus_set_socket用来改变上下文中保存的客户连接可以接受多个连接然后用select来选择可以操作的连接然后先设置modbus_set_socket再modbus_receive。 因为我没有试所以没有示例代码。 这里是文档结束