有限狀态機
有限狀态機——邏輯單元内部的一種高效程式設計方法。
有的應用層協定頭部包含資料包類型字段,每種資料類型可以映射為邏輯單元的一種執行狀态,伺服器可以根據它來編寫相應的處理邏輯
獨立的有限狀态機
該狀态機的每個狀态都是互相獨立的,狀态之間沒有互相轉移。
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;
}
}
}
#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\n", "Something wrong\n" };
/*從狀态機,用幹解析出一行内容,初始狀态為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];
/*如果目前的位元組是“\r”,即到車符,則說明可能讀取到一個完整的行*/
if(temp=='\r')
{
/*如果“\r"是buff最後一個被讀入的資料,這次沒有讀取到完整的一行*/
if((checked_index+1)==read_index)
return LINE_OPEN;
else if(temp[checked_index+1]=='\n')//下一個字元是\n,讀取到完整的一行
{
buffer[checked_index++]='\0';
buffer[checked_index++]='\0';
return LINE_OK;
}
return LINE_BAD;
}
else if(temp=='\n')
{
if((checked_index-1)>0&&temp[checked_index-1]=='\r')
{
buffer[checked_index++]='\0';
buffer[checked_index++]='\0';
return LINE_OK;
}
}
return LINE_BAD;
}
return LINE_OPEN;
}
HTTP_CODE praseRequestLine(char *temp,CHECK_STATE &state)
{
char *url=strpbrk(temp,"\t");
if(!url)
{
return BAD_REQUEST;
}
*url++='\0';
char *method=temp;
if(strcasecmp(method."GET")==0)
{
printf("method id GET");
}
else
{
return BAD_REQUEST;
}
url+=strspn(url,"\t");
char *version=strpbrk(url,"\t");
if(!version)
{
return BAD_REQUEST;
}
*version++='\0';
version+=strspn(version,"\t");
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:\n",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,"\t");
printf("the request host is: \n",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,'\0',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;
}