APUE-树莓派温度监控项目-断线重连
1、说明
客户端需要实现一下功能
- 如果网络socket异常(如网络断线、服务器端退出),在网络故障恢复后客户端程序能够自动重连;
- 在网络故障出错期间,定时采样正常进行,在此瞬间所有采样的数据(临时存储到SQLite数据库中;
- 网络故障恢复之后,客户端程序自动将之前暂存到数据库中的数据上报销服务器上去, 并从里面删除。
我原本打算直接通过send()==0判断服务器端关闭连接,但后面发现这样不好实现其他功能。
另外,我写的重连函数reconnect_socket()函数在重连成功后才会返回,这会导致断连期间数据只存储了一次
//断线重连 int reconnect_socket(char *serv_ip,int port) { int retry_count = 0; int conn_fd = -1; while( conn_fd < 0 && retry_count < MAX_RETRY_COUNT) { conn_fd = connect_socket(serv_ip, port); if( conn_fd < 0 ) { dbg_print("Failed to reconnect:%s\n",strerror(errno)); retry_count++; close(conn_fd); sleep(5); } else { dbg_print("Reconnect successfully,new fd:%d\n", conn_fd); break; } } return conn_fd; }
2、getsockopt()/setsockopt()函数
#include <sys/types.h> #include <sys/socket.h> int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen); int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); 返回值:若成功则返回0,若出错则返回-1
参数说明:
- sockfd:必须指向一个打开的套接字描述符。
- level:标识了选项应用的协议。
- optname:要设置或获取套接字选项的名字。
- optval:指向函数设置或获取值得地址,即保存选项值的缓存区。
- optlen:指定了optval指向的对象的大小。
3、实现代码:
int sock_opt; struct tcp_info optval;//获取状态信息 int opt_len = sizeof(optval); int net_state = 1; db = open_database(); conn_fd = connect_socket(serv_ip, port); while(1) { sock_opt = getsockopt(conn_fd,IPPROTO_TCP,TCP_INFO,&optval,(socklen_t *)&opt_len); if( net_state)//正常 { if( optval.tcpi_state != TCP_ESTABLISHED )//optval.tcpi_state表示当前连接状态,TCP_ESTABLISHED 状态,即已建立连接。如果连接状态不是 TCP_ESTABLISHED,则表明连接已断开 { net_state = 0;//将网络状态标记为故障 dbg_print("Server disconnect.\n"); } else//连接正常,发送数据 { rv = data_string(s_buf); send_size = send_data(conn_fd,s_buf); if( send_size < 0 )//发送失败 { dbg_print("Send data failure:%s\n",strerror(errno)); } } } else //网络状态故障 { rv = get_temperature(&temperature); rv = get_datetime(datetime); store_database(db,&temperature,datetime);//将数据暂存扫数据库中 dbg_print("Data saved to database:%.2f %s\n",temperature, datetime); conn_fd = connect_socket(serv_ip,port);//重连 if( conn_fd > 0 )//成功 { net_state = 1;//重连成功,将网络状态标记为正常 select_database(db, conn_fd);//发送数据库中的数据 } } } delete_database(db); close(conn_fd); sqlite3_close(db);
本文作者:梨子Li
本文链接:https://www.cnblogs.com/LiBlog--/p/18072747
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步