当前位置: 首页 > news >正文

温州网站建设培训班俄语淘宝网站建设

温州网站建设培训班,俄语淘宝网站建设,用cms做网站的缺点,公司企业展厅设计公司2. 结合代码分析请求报文解析 上一节我们对http连接的基础知识、服务器接收请求的处理流程进行了介绍#xff0c;接下来将结合流程图和代码分别对状态机和服务器解析请求报文进行详解。 流程图部分#xff0c;描述主、从状态机调用关系与状态转移过程。 代码部分#xff…2. 结合代码分析请求报文解析 上一节我们对http连接的基础知识、服务器接收请求的处理流程进行了介绍接下来将结合流程图和代码分别对状态机和服务器解析请求报文进行详解。 流程图部分描述主、从状态机调用关系与状态转移过程。 代码部分结合代码对http请求报文的解析进行详解。 2.1 流程图与状态机 从状态机负责读取报文的一行主状态机负责对该行数据进行解析主状态机内部调用从状态机从状态机驱动主状态机。 主状态机 三种状态标识解析位置。 CHECK_STATE_REQUESTLINE解析请求行CHECK_STATE_HEADER解析请求头CHECK_STATE_CONTENT解析消息体仅用于解析POST请求 从状态机 三种状态标识解析一行的读取状态。 LINE_OK完整读取一行LINE_BAD报文语法有误LINE_OPEN读取的行不完整 2.2 代码分析-http报文解析 上节中介绍了服务器接收http请求的流程与细节简单来讲浏览器端发出http连接请求服务器端主线程创建http对象接收请求并将所有数据读入对应buffer将该对象插入任务队列后工作线程从任务队列中取出一个任务进行处理。 各子线程通过process函数对任务进行处理调用process_read函数和process_write函数分别完成报文解析与报文响应两个任务。 void http_conn::process() {HTTP_CODE read_retprocess_read();//NO_REQUEST表示请求不完整需要继续接收请求数据if(read_retNO_REQUEST){//注册并监听读事件modfd(m_epollfd,m_sockfd,EPOLLIN);return;}//调用process_write完成报文响应bool write_retprocess_write(read_ret);if(!write_ret){close_conn();}//注册并监听写事件modfd(m_epollfd,m_sockfd,EPOLLOUT); }本节将对报文解析的流程和process_read函数细节进行详细介绍。 HTTP_CODE含义 表示HTTP请求的处理结果在头文件中初始化了八种情形在报文解析时只涉及到四种。 NO_REQUEST 请求不完整需要继续读取请求报文数据GET_REQUEST 获得了完整的HTTP请求BAD_REQUEST HTTP请求报文有语法错误INTERNAL_ERROR 服务器内部错误该结果在主状态机逻辑switch的default下一般不会触发 解析报文整体流程 process_read通过while循环将主从状态机进行封装对报文的每一行进行循环处理。 判断条件 主状态机转移到CHECK_STATE_CONTENT该条件涉及解析消息体从状态机转移到LINE_OK该条件涉及解析请求行和请求头部两者为或关系当条件为真则继续循环否则退出循环体 从状态机读取数据调用get_line函数通过m_start_line将从状态机读取数据间接赋给text主状态机解析text //m_start_line是行在buffer中的起始位置将该位置后面的数据赋给text //此时从状态机已提前将一行的末尾字符\r\n变为\0\0所以text可以直接取出完整的行进行解析 char* get_line(){return m_read_bufm_start_line; }http_conn::HTTP_CODE http_conn::process_read() {//初始化从状态机状态、HTTP请求解析结果LINE_STATUS line_statusLINE_OK;HTTP_CODE retNO_REQUEST;char* text0;//这里为什么要写两个判断条件第一个判断条件为什么这样写//具体的在主状态机逻辑中会讲解。//parse_line为从状态机的具体实现while((m_check_stateCHECK_STATE_CONTENT line_statusLINE_OK)||((line_statusparse_line())LINE_OK)){textget_line();//m_start_line是每一个数据行在m_read_buf中的起始位置//m_checked_idx表示从状态机在m_read_buf中读取的位置m_start_linem_checked_idx;//主状态机的三种状态转移逻辑switch(m_check_state){case CHECK_STATE_REQUESTLINE:{//解析请求行retparse_request_line(text);if(retBAD_REQUEST)return BAD_REQUEST;break;}case CHECK_STATE_HEADER:{//解析请求头retparse_headers(text);if(retBAD_REQUEST)return BAD_REQUEST;//完整解析GET请求后跳转到报文响应函数else if(retGET_REQUEST){return do_request();}break;}case CHECK_STATE_CONTENT:{//解析消息体retparse_content(text);//完整解析POST请求后跳转到报文响应函数if(retGET_REQUEST)return do_request();//解析完消息体即完成报文解析避免再次进入循环更新line_statusline_statusLINE_OPEN;break;}default:return INTERNAL_ERROR;}}return NO_REQUEST; }从状态机逻辑 上面基础知识讲解中对于HTTP报文的讲解遗漏了一点细节在这里作为补充。 在HTTP报文中每一行的数据由\r\n作为结束字符空行则是仅仅是字符\r\n。因此可以通过查找\r\n将报文拆解成单独的行进行解析项目中便是利用了这一点。 从状态机负责读取buffer中的数据将每行数据末尾的\r\n置为\0\0并更新从状态机在buffer中读取的位置m_checked_idx以此来驱动主状态机解析。 从状态机从m_read_buf中逐字节读取判断当前字节是否为\r 接下来的字符是\n将\r\n修改成\0\0将m_checked_idx指向下一行的开头则返回LINE_OK接下来达到了buffer末尾表示buffer还需要继续接收返回LINE_OPEN否则表示语法错误返回LINE_BAD当前字节不是\r判断是否是\n一般是上次读取到\r就到了buffer末尾没有接收完整再次接收时会出现这种情况 如果前一个字符是\r则将\r\n修改成\0\0将m_checked_idx指向下一行的开头则返回LINE_OK当前字节既不是\r也不是\n 表示接收不完整需要继续接收返回LINE_OPEN if(m_checked_idx1m_read_buf[m_checked_idx-1]\r){m_read_buf[m_checked_idx-1]\0;m_read_buf[m_checked_idx]\0;return LINE_OK;}return LINE_BAD;}}//并没有找到\r\n需要继续接收return LINE_OPEN; }主状态机逻辑 主状态机初始状态是CHECK_STATE_REQUESTLINE通过调用从状态机来驱动主状态机在主状态机进行解析前从状态机已经将每一行的末尾\r\n符号改为\0\0以便于主状态机直接取出对应字符串进行处理。 CHECK_STATE_REQUESTLINE 主状态机的初始状态调用parse_request_line函数解析请求行解析函数从m_read_buf中解析HTTP请求行获得请求方法、目标URL及HTTP版本号解析完成后主状态机的状态变为CHECK_STATE_HEADER //解析http请求行获得请求方法目标url及http版本号 http_conn::HTTP_CODE http_conn::parse_request_line(char *text) {//在HTTP报文中请求行用来说明请求类型,要访问的资源以及所使用的HTTP版本其中各个部分之间通过\t或空格分隔。//请求行中最先含有空格和\t任一字符的位置并返回m_urlstrpbrk(text, \t);//如果没有空格或\t则报文格式有误if(!m_url){return BAD_REQUEST;}//将该位置改为\0用于将前面数据取出*m_url\0;//取出数据并通过与GET和POST比较以确定请求方式char *methodtext;if(strcasecmp(method,GET)0)m_methodGET;else if(strcasecmp(method,POST)0){m_methodPOST;cgi1;}elsereturn BAD_REQUEST;//m_url此时跳过了第一个空格或\t字符但不知道之后是否还有//将m_url向后偏移通过查找继续跳过空格和\t字符指向请求资源的第一个字符m_urlstrspn(m_url, \t);//使用与判断请求方式的相同逻辑判断HTTP版本号m_versionstrpbrk(m_url, \t);if(!m_version)return BAD_REQUEST;*m_version\0;m_versionstrspn(m_version, \t);//仅支持HTTP/1.1if(strcasecmp(m_version,HTTP/1.1)!0)return BAD_REQUEST;//对请求资源前7个字符进行判断//这里主要是有些报文的请求资源中会带有http://这里需要对这种情况进行单独处理if(strncasecmp(m_url,http://,7)0){m_url7;m_urlstrchr(m_url,/);}//同样增加https情况if(strncasecmp(m_url,https://,8)0){m_url8;m_urlstrchr(m_url,/);}//一般的不会带有上述两种符号直接是单独的/或/后面带访问资源if(!m_url||m_url[0]!/)return BAD_REQUEST;//当url为/时显示欢迎界面if(strlen(m_url)1)strcat(m_url,judge.html);//请求行处理完毕将主状态机转移处理请求头m_check_stateCHECK_STATE_HEADER;return NO_REQUEST; } 解析完请求行后主状态机继续分析请求头。在报文中请求头和空行的处理使用的同一个函数这里通过判断当前的text首位是不是\0字符若是则表示当前处理的是空行若不是则表示当前处理的是请求头。 CHECK_STATE_HEADER 调用parse_headers函数解析请求头部信息判断是空行还是请求头若是空行进而判断content-length是否为0如果不是0表明是POST请求则状态转移到CHECK_STATE_CONTENT否则说明是GET请求则报文解析结束。若解析的是请求头部字段则主要分析connection字段content-length字段其他字段可以直接跳过各位也可以根据需求继续分析。connection字段判断是keep-alive还是close决定是长连接还是短连接content-length字段这里用于读取post请求的消息体长度 //解析http请求的一个头部信息 http_conn::HTTP_CODE http_conn::parse_headers(char *text) {//判断是空行还是请求头if(text[0]\0){//判断是GET还是POST请求if(m_content_length!0){//POST需要跳转到消息体处理状态m_check_stateCHECK_STATE_CONTENT;return NO_REQUEST;}return GET_REQUEST;}//解析请求头部连接字段else if(strncasecmp(text,Connection:,11)0){text11;//跳过空格和\t字符textstrspn(text, \t);if(strcasecmp(text,keep-alive)0){//如果是长连接则将linger标志设置为truem_lingertrue;}}//解析请求头部内容长度字段else if(strncasecmp(text,Content-length:,15)0){text15;textstrspn(text, \t);m_content_lengthatol(text);}//解析请求头部HOST字段else if(strncasecmp(text,Host:,5)0){text5;textstrspn(text, \t);m_hosttext;}else{printf(oop!unknow header: %s\n,text);}return NO_REQUEST; }如果仅仅是GET请求如项目中的欢迎界面那么主状态机只设置之前的两个状态足矣。 前面提到过GET和POST请求报文的区别之一是有无消息体部分GET请求没有消息体当解析完空行之后便完成了报文的解析。 但后续的登录和注册功能为了避免将用户名和密码直接暴露在URL中我们在项目中改用了POST请求将用户名和密码添加在报文中作为消息体进行了封装。 为此我们需要在解析报文的部分添加解析消息体的模块。 while((m_check_stateCHECK_STATE_CONTENT line_statusLINE_OK)||((line_statusparse_line())LINE_OK)) 那么这里的判断条件为什么要写成这样呢 在GET请求报文中每一行都是\r\n作为结束所以对报文进行拆解时仅用从状态机的状态line_statusparse_line())LINE_OK语句即可。 但在POST请求报文中消息体的末尾没有任何字符所以不能使用从状态机的状态这里转而使用主状态机的状态作为循环入口条件。 那后面的 line_statusLINE_OK又是为什么 解析完消息体后报文的完整解析就完成了但此时主状态机的状态还是CHECK_STATE_CONTENT也就是说符合循环入口条件还会再次进入循环这并不是我们所希望的。 为此增加了该语句并在完成消息体解析后将line_status变量更改为LINE_OPEN此时可以跳出循环完成报文解析任务。 CHECK_STATE_CONTENT 仅用于解析POST请求调用parse_content函数解析消息体用于保存post请求消息体为后面的登录和注册做准备 //判断http请求是否被完整读入 http_conn::HTTP_CODE http_conn::parse_content(char *text) {//判断buffer中是否读取了消息体if(m_read_idx(m_content_lengthm_checked_idx)){text[m_content_length]\0;//POST请求中最后为输入的用户名和密码m_string text;return GET_REQUEST;}return NO_REQUEST; }状态机和HTTP报文解析是项目中最繁琐的部分这次我们一举解决掉它希望对各位小伙伴在理解项目的过程中有所帮助。
http://www.pierceye.com/news/659469/

相关文章:

  • 电商网站建设综述湖北seo网站设计
  • 南京做网站营销网站后台忘记账号密码
  • 敦化建设局网站饰品做国际贸易哪些网站
  • 网站做js跳转怎么创建公司
  • 网站建设合同需要交印花税吗怎么做网站卖美瞳
  • 小程序价格为什么比网站建设高自定义wordpress的实用技巧
  • 企业网站模板源码有哪些报价网站制作
  • 网站建设与网页设计实训报告二级建造师建设云网站
  • 网站后缀gov汕头网站建设小程序
  • 一个空间做多个网站wordpress大改动
  • 桂林北站到机场大巴专线时刻表wordpress 分类 标签
  • 自媒体网站源码模板dede重庆永川网站建设报价
  • 国外酷炫网站网页前端设计流程
  • 子午谷网站建设世界杯网页设计素材
  • 关于网站建设申请报告电商网站建设价位
  • 网站评价系统源码wordpress笔记本主题
  • 大庆市建设大厦网站广告设计海报
  • 惠州建设工程交易网站网络营销专业的职业生涯规划
  • 网站页面架构图阿里云的企业网站建设
  • 做微商网站有专门做网站的公司吗
  • 潍坊网站建设方案托管天津建站网
  • 前端如何做双语网站信誉好的唐山网站建设
  • 创建网站目录应注意电子商务类网站设计
  • 哪个网站专做进口商品的企业网站建设的方案ppt
  • 网站结构如何优化wordpress4.7.10漏洞
  • 官方网站举例流量型网站
  • DW个人网站怎么做长沙民企人才网
  • 电脑做网站教学友情链接交易
  • 为什么选php语言做网站重庆网站优化seo公司
  • 仿站侵权吗字体设计图片