• 有限状态机


      有限状态机——逻辑单元内部的一种高效编程方法。

      有的应用层协议头部包含数据包类型字段,每种数据类型可以映射为逻辑单元的一种执行状态,服务器可以根据它来编写相应的处理逻辑

    独立的有限状态机

      该状态机的每个状态都是相互独立的,状态之间没有相互转移。

     state_machine(Package _pack)
        {
            PackageType _type=_pack.getType();
            switch(_type)
            {
            case type_A:
                process_package_A(_pack);
                break;
            case type_B:
                process_package_B(_pack);
                break;
            }
        }

    带状态转移的有限状态机

      状态的转移需要状态机的内部驱动

    STATE_MACHINE()
    {
        State curState=type_A;
        while(curState!=type_C)
        {
            Package  _pack=getNewPackage();//获得一个新的数据包
            switch(curState)
            {
            case type_A:
                process_package_state_A(_pack);
                curState=type_B;
                break;
            case type_B:
                process_package_state_B(_pack);
                curState=type_C;
                break;
            }
        }
    }

     code

    #include <sys/socket .h>
    #include <netinet/in.h>
    #include carpa/inet.h>
    #include <ssert.h>
    #include cstdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <orrno.h>
    #include <string.h>
    #include <fcnt1.h>
    #define BUFFER SIZB 4096/读缓冲区大小
    /*主状态机的两种可能状态,分别表示当前正在分析请求行,当南正在分析头邮字段*/
    enum CHECK_STATE
    {
        CRECK_STATE_REQUESTLINE=0,CHECK_STATE_HEADER
    };
    /*从状态机的三种可能状态,即行的读取状态,分别表示:读取到一个完整的行、行出错和行数据尚目不完整*/
    enum LINE_STATUS
    {
        LINE_OK=0,LINE_BAD,LINE_OPEN
    };
    /*服务器处理了http请求的结来:NO_REQUEST表示请求不完整,需要续读取客户数据;GET_REOUEST表示获得了1个完警的客户清求;
    BAD_REQUEST表示客户请求有语法错误;FORBIDDEN_REOUEST表示客户对资源没有足够的访问权限;INTERNALL_ERROR表示服务器内部错误;
    CLOSED_CONECTION:表示家户端已经关闭连接*/
    enum HTTP_CODE
    {
        NO_REQUEST,GET_REQUEST,BAD_REQUEST,FORBIDDEN_REQUEST,INTERNALL_ERROR,CLOSED_CONNECTON
    };
    /*为了简化问题,我们没有给客户端发送一个完整的HTTP应答报文,面只是极据服务器的处理结果发送如下威功或失败信息*/
    static const char* szret[]={"I get a correct result
    ", "Something wrong
    " };
    
    /*从状态机,用干解析出一行内容,初始状态为OK,原始驱动力来自于buffer中新到来的数据*/
    LINE_STATUS praseLine(char* buffer,int& checked_index, int& read_index)
    {
        char temp;
        /* checked index指向buffer (应用程序的读缓冲区)中当前正在分析的字节。read index指向buffer中客户数据的尾部的下一字节
        buffer中第0-checkedindex字节都已分析完率,第checkedindex- (read index-11 字节由下面的循环挨个分析*/
        for(;checked_index<read_index;++checked_index)
        {
            /*获得当前要分析的字节*/
            temp=butfer[checked_index];
            /*如果当前的字节是“
    ”,即到车符,则说明可能读取到一个完整的行*/
            if(temp=='
    ')
            {
                /*如果“
    "是buff最后一个被读入的数据,这次没有读取到完整的一行*/
                if((checked_index+1)==read_index)
                    return LINE_OPEN;
                else if(temp[checked_index+1]=='
    ')//下一个字符是
    ,读取到完整的一行
                {
                    buffer[checked_index++]='';
                    buffer[checked_index++]='';
                    return LINE_OK;
                }
                return LINE_BAD;
            }
            else if(temp=='
    ')
            {
                if((checked_index-1)>0&&temp[checked_index-1]=='
    ')
                {
                    buffer[checked_index++]='';
                    buffer[checked_index++]='';
                    return LINE_OK;
                }
            }
            return LINE_BAD;
        }
        return LINE_OPEN;
    }
    
    HTTP_CODE praseRequestLine(char *temp,CHECK_STATE &state)
    {
        char *url=strpbrk(temp,"	");
        if(!url)
        {
            return BAD_REQUEST;
        }
        *url++='';
    
        char *method=temp;
        if(strcasecmp(method."GET")==0)
        {
            printf("method id GET");
        }
        else
        {
            return BAD_REQUEST;
        }
    
        url+=strspn(url,"	");
        char *version=strpbrk(url,"	");
        if(!version)
        {
            return BAD_REQUEST;
        }
        *version++='';
        version+=strspn(version,"	");
        if(strcasecmp(version,"HTTP/1.1")!=0)
        {
            return BAD_REQUEST;
        }
        if(strncasecmp(url,"http://",7)==0)
        {
            url+=7;
            url=strchr(url,'/');
        }
        if(!url||url[0]!='/')
            return BAD_REQUEST;
    
        printf("The request url is:
    ",url);
        state=CHECK_STATE_HEADER;//解析完请求行后将其设置为CHECK_STATE_HEADER,来实现状态转移
        return NO_REQUEST;
    }
    
    HTTP_CODE parseHeaders(char *temp)
    {
        if(temp[0]=='0')
            return GET_REQUEST;
        else if(strncasecmp(temp,"Host:",5)==0)
        {
            temp+=5;
            temp+=strspn(temp,"	");
            printf("the request  host is: 
    ",temp);
        }
        else
        {
            perror("not handle this header");
        }
        return NO_REQUEST;
    }
    //http 请求入口函数
    HTTP_CODE praseContent(char *buffer,int *checkedIndex,CHECK_STATE &state,int &readIndex,int &startLine)
    {
        LINE_STATUS lineStatus=LINE_OK;
        HTTP_CODE resCode=NO_REQUEST;
    
        //
        while((lineStatuse=parseLine(buffer,checkedIndex,readIndex))==LINE_OK)
        {
            char *temp=buffer+startLine;//startLIine是在buffer中的起始位置
            startLine=checkedIndex;
            switch(state)
            {
            case CHECK_STATE_REQUESTLINE://请求行
            {
                resCode=parseRquestLine(temp,state);
                if(resCode==BAD_REQUEST)
                    return BAD_REQUEST;
                break;
            }
            case CHECK_STATE_HEADER://头部字段
            {
                resCode=parseHEADERS(temp);
                if(resCode==BAD_REQUEST)
                    return BAD_REQUEST;
                else if(resCode==GET_REQUEST)
                    return GET_REQUEST;
                break;
            }
            default:
                return INTERNALL_ERROR;
            }
        }
        //若没有读取到完整的一行,需要继续读
        if(LINE_STATUS==LINE_OPEN)
            return NO_REQUEST;
        else
            return BAD_REQUEST;
    }
    
    int main()
    {
        //基本的tcp链接操作
    
        char buffer[BUFFER_SIZE];
        memset(buffer,'',BUFFER_SIZE);
        int dataRead=0;
        int readIndex=0;//当前已经读取了多少个字节的客户数据
        int checkedIndex=0;//当前已经分析了多少个客户字节的数据
        int startLine=0;//行在buffer中的起始位置
    
        //设置主机的初始状态,表示当前状态为请求行,解析完请求行后变为CHECK_STATE_HEADER实现状态转移
        CHECK_STATE state=CHECK_STATE_REQUESTLINE;
        while(true)
        {
            dataRead=recv(fd,buffer+readIndex,BUFFER_SIZE-readIndex,0);
            if(dataRead==-1)
            {
                perror("read failed");
                break;
            }
            else if(dataRead==0)
            {
                perror("remote client has closed the connection");
                break;
            }
            readIndex+=dataRead;
    
            //读取数据成功后,分析目前已经得到的数据
            HTTP_CODE res=parseContent(buffer,checkedIndex,state,readIndex,starLine);
            if(res==NO_REQUEST)
            {
                continue;
            }
            else if(res==GET_REQUEST)
            {
                send(fd,szret[0],strlen(szret[0]),0);
            }
            else//error
            {
                send(fd,szret[1],strlen(szret[1]),0);
                break;
            }
            close(fd);
        }
        close(listenfd);
        return 0;
    }
  • 相关阅读:
    简单的购物车
    分页显示
    登录验证码的实现
    简单遗传算法代码
    jQ
    2.servlet的会话机制session
    1.servlet的会话机制cookie
    基本数据类型和引用数据类型的区别
    struts2-第一章-基础用法2
    struts2第一章-基本用法
  • 原文地址:https://www.cnblogs.com/tianzeng/p/10780933.html
Copyright © 2020-2023  润新知