专业的编程技术博客社区

网站首页 > 博客文章 正文

状态机的简单应用(状态机的优点)

baijin 2024-10-01 07:34:18 博客文章 8 ℃ 0 评论

状态机的简单应用

本文主要从三个方面来说状态机的应用

  • 状态机的简单介绍

  • 从项目需求上来说

  • 结合代码来说

简单介绍

表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型,其实这些都是书面语,解释的已经很清楚了;通俗的来说状态机就是在各个状态之间循环,精髓是循环

项目需求

做的这个项目主要是视频采集相关的,主要分为三块儿内容,手机APP端,云端,设备端;当用户需要看视频时候可以通过手机APP点击按钮来查看想看的内容,比如用户需要看视频就需要点击拉视频流的按钮,进而发送命令到云端,云端经过处理然后把命令发给设备端,设备端执行相应的功能,由于我主要是做设备端这一块儿,我就从设备端这一块儿简短介绍一下主要需求

  • 开机自启动,设备开机应该自动连接到云端(主要用到/etc/rc.local文件)

  • 设备端应该能控制摄像头的一些动作(主要用到串口编程的知识,多线程编程)

  • 当服务端出现异常应该保证设备端不会退出,当服务端恢复时应该能主动连接上(主要用状态机来实现)

  • 远程更新(主要用到的是ssh反向端口转发知识)

  • 流量监控(主要用到的是状态机,AT指令的知识)

    下面以一张图来说明一下状态机

状态机

图画的有点儿乱,在这里解释一下,设备端程序主要分为四大部分,也就是四大状态

连接,注册登陆,处理命令,心跳;

  • 连接到服务端,如果服务端出现异常设备端程序就会一直在这一部分循环直到服务端恢复正常

  • 连接到服务端以后,就是登陆注册,设备端把用户名,密码发到服务端验证,如果验证不成功就接着验证,如果验证10次还没成功就返回到连接状态,如果成功就进行下一步处理命令

  • 如果处理失败10次就返回到连接状态,处理完命令5秒没有再收到任何命令就进到心跳状态

  • 如果设备端登陆成功后在5秒内没有收到服务端发过来的任何消息那么进到心跳状态

    总之无论服务端有何异常断开的行为设备端都不会断开,一直下循环

结合代码

  • 首先定义几个状态

enum{

START=0,

LOGGING=1,

PROCESSING=2,

HEARTBEAT=3

};

  • 定义以后就是具体实现了,因为状态机的精髓就是循环,所以我们的状态都在一个while里面,这是第一个状态

while(1)

{

switch(state){

case START:

if(sockfd !=0)

close(sockfd);

if((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1) {

perror("sock");

state = START; //如果建立套接字错误返回到START状态

break;

}

bzero(&address,sizeof(address));

address.sin_family = AF_INET;

address.sin_port = htons(atoi(argv[2]));

inet_pton(AF_INET,argv[1],&address.sin_addr);

len = sizeof(address);

if((result = connect(sockfd, (struct sockaddr *)&address, len))==-1) {

perror("connect");

state = START; //如果连接不上就返回到START状态

break;

}

state = LOGGING; //如果建立套接字,连接都正确就跳到下一登陆状态

state_logging_c=0;

break;

  • 登陆状态

case LOGGING:

ret = login_c(sockfd);//1 stands for success

state_logging_c+=1;

if(ret < 0)//failure

{

if(state_logging_c > 10) //如果登陆十次都登录不上,那么就返回到START状态

state = START;

else

state = LOGGING;

break;

}

printf("LOGIN SUCESS!\n");

state = PROCESSING; //如果登陆成功就进入到下一个处理命令状态

state_processing_c = 0;

state_processing_fail = 0;

break;

  • 处理命令的状态

case PROCESSING:

state_processing_c++;

FD_ZERO(&rfds);

FD_SET(0, &rfds);

maxfd = 0;

FD_SET(sockfd, &rfds);

if (sockfd > maxfd)

maxfd = sockfd;

tv.tv_sec = 5; //if server don't send any commnad to us within 5s, then we send a hearbeat to the server

tv.tv_usec = 0;

retval = select(maxfd+1, &rfds, NULL, NULL, &tv);

if(retval == -1){

printf("select is error\n");

if(state_processing_c >10) //如果调用select错误十次,那么也返回到START状态

state = START;

else

state = PROCESSING;//如果在十次只能有成功的就接着返回到PROCESSING状态循环

break;

}

else if(retval ==0){ //retval=0说明超时,说明在5秒之内没有收到任何命令,那么就进入到心跳状态

state = HEARTBEAT;

break;

}

//now retval >0 ,we have command to dealwith

if (FD_ISSET(sockfd, &rfds))

{

bzero(buffer, MAXBUF+1);

// len = recv(sockfd, buffer, MAXBUF, 0);

len = recv(sockfd, buffer, sizeof(buffer),0);

printf("len = %d\n",len);

if (len > 0)

{

keepflag = 0;

//处理服务端发过来的命令上下左右

process_command(buffer,sockfd);

}

else

{

sleep(3);

state_processing_fail++;

if(state_processing_fail > 10) //如果命令处理十次都失败,那就返回到START状态重新连接

{

state=START;

printf("we switch to START state because we cannot receive message from server\n");

break;

}

printf("Failed to receive the message! \n");

}

}

  • 心跳状态(心跳的作用就是当没有命令发送的时候确定服务端是否正常)

case HEARTBEAT:

len = send(sockfd, heartbeat, strlen(heartbeat), 0); //发送心跳包

if (len < 0)

{

printf("failed to send heartbeat !\n");//in this case, we also add keepflag by 1,to switch the state to START

}

else

{

printf("%d\n",keepflag);

printf("error = %d\n",errno);//use the debug

printf("heartbeat send!\n");

keepflag += 1;

if(keepflag > 10){ //发了十次心跳包服务端都没有回应,默认服务端已经挂了,就返回到START状态

state = START;

printf("we switch to START state because we sent 20 times heartbeat that but the server not sent us\n");

keepflag = 0;

break;

}

}

state = PROCESSING; //如果接收到命令就跳到处理命令状态

state_processing_c =0;

state_processing_fail =0;

break;

default:

state = START;

break;

}//switch state machine

}//while(1)

exit(0);

}

这是很简单的应用,代码没有难度,我就不一一说了,就把一些重要的注释了一下,感觉无论简单复杂,要有场景,在场景里学习是可以事半功倍的

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表