两种情况的根本原因都是 服务端未正确处理连接关闭后的资源释放,导致:
modbus_receive()。修改服务端代码逻辑,核心思路:超时检测 + 连接资源释放 + 循环等待新连接。
设置响应超时时间
modbus_t *ctx = modbus_new_tcp("127.0.0.1", 1502);
struct timeval timeout;
timeout.tv_sec = 1; // 1秒超时(根据需求调整)
timeout.tv_usec = 0;
modbus_set_response_timeout(ctx, &timeout);重构服务端主循环
int server_socket = modbus_tcp_listen(ctx, 1); // 创建监听socket
while (1) {
// 1. 等待客户端连接到
if (modbus_tcp_accept(ctx, &server_socket) == -1) {
fprintf(stderr, "Accept failed: %sn", modbus_strerror(errno));
continue; // 继续等待新连接
}
// 2. 连接建立后处理请求
while (1) {
uint8_t req[MODBUS_TCP_MAX_ADU_LENGTH];
int rc = modbus_receive(ctx, req);
if (rc == -1) {
// 错误处理:超时或连接断开
if (errno == ETIMEDOUT) {
printf("Client timeout. Closing connection.n");
} else {
printf("Connection reset: %sn", modbus_strerror(errno));
}
break; // 退出内部循环,准备接受新连接
}
// 处理Modbus请求(示例)
if (req[7] == 0x03) { // 功能码03
uint16_t reg[2] = {0x1234, 0x5678};
modbus_reply(ctx, req, 5, reg); // 返回数据
}
}
// 3. 关闭当前失效连接
modbus_close(ctx);
printf("Connection closed. Waiting for new client...n");
}编译时链接库
gcc server.c -o modbus_server -lmodbus超时检测
modbus_set_response_timeout() 设置读超时后,modbus_receive() 会在指定时间后返回 -1 并设置 errno=ETIMEDOUT,避免永久阻塞。
双重循环结构
modbus_tcp_accept)资源清理
modbus_close() 释放当前连接资源,使服务端能重新绑定端口监听新连接。
graph TD
A[启动服务] --> B[监听端口]
B --> C{有新连接?}
C -- 是 --> D[建立连接]
D --> E{接收数据}
E -- 成功 --> F[处理请求]
F --> E
E -- 超时/错误 --> G[关闭连接]
G --> C
C -- 否 --> C客户端短连接优化
客户端每次请求后调用 modbus_close() 主动断开,避免服务端等待超时。
服务端健壮性增强
// 在 modbus_tcp_accept 前添加 SO_REUSEADDR 避免端口占用
int reuse = 1;
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));处理连接中断信号
// 在 modbus_receive 后检查特定错误码
if (rc == -1 && (errno == ECONNRESET || errno == EPIPE)) {
printf("Client forcibly closed connectionn");
break;
}
关键点:服务端必须主动释放旧连接资源(
modbus_close),才能接受新连接。超时设置避免了服务端永久阻塞,双重循环结构保证了连接重置能力。
举报
更多回帖