这里所说的错误有两种:
1.http协议规定的错误,如404错误。
2.server执行过程中的错误。如write错误。

对于http协议规定的错误,这里的“错误”是针对client的。

lighttpd返回相应的错误提示文件之后,相当于顺利的完毕了一次请求,仅仅是结果和client想要的不一样而已。

对于server执行中的错误,状态机进入CON_STATE_ERROR状态。常见的错误原因:client提前断开连接。

比方你不停的刷新页面。在你刷新的时候,前一次的连接没有完毕,但被浏览器强行断开。对于server而言,刷新前后的两个连接是不相干的,server在接收后一个连接的时候仍然会继续处理前一次的连接。而前一次的连接已断开,这就产生了连接错误。

进入CON_STATE_ERROR状态后。假设前面的请求处理已经得到了结果。也就是http_status不为空。那么调用plugins_call_handle_request_done告诉插件请求处理结束:

            /* even if the connection was drop we still have to write it to the access log */if (con->http_status) {plugins_call_handle_request_done(srv, con);}

假设使用了ssl,关闭ssl连接:

#ifdef USE_OPENSSLif (srv_sock->is_ssl) {/* 关闭ssl连接 */}ERR_clear_error();
#endif

接着:

            switch(con->mode) {case DIRECT:
#if 0log_error_write(srv, __FILE__, __LINE__, "sd","emergency exit: direct",con->fd);
#endifbreak;default:switch(r = plugins_call_handle_connection_close(srv, con)) {case HANDLER_GO_ON:case HANDLER_FINISHED:break;default:log_error_write(srv, __FILE__, __LINE__, "");break;}break;}connection_reset(srv, con);

假设连接模式不是DIRECT,调用plugins_call_handle_connection_close告诉插件连接已经关闭。

假设设置了keep_alive。此时可能是server首先关闭连接的。调用shutdown关闭连接的读和写。假设关闭没有出错,状态机进入CON_STATE_CLOSE状态。

假设没有设置keep_alive或者shutdown调用失败,那么直接关闭连接。结束状态机的执行。

            /* close the connection */if ((con->keep_alive == 1) &&(0 == shutdown(con->fd, SHUT_WR))) {con->close_timeout_ts = srv->cur_ts;connection_set_state(srv, con, CON_STATE_CLOSE);if (srv->srvconf.log_state_handling) {log_error_write(srv, __FILE__, __LINE__, "sd","shutdown for fd", con->fd);}} else {connection_close(srv, con);}con->keep_alive = 0;srv->con_closed++;

注意到。这里server主动关闭连接的时候用的是shutdown而不是close:

1.close使用引用计数,在计数为0时才关闭套接字;shutdown无论引用计数,直接激发TCP的正常连接终止序列。

2.close终止读和写两个方向的数据传送。shutdown能够指定仅仅关闭连接的读,或仅仅关闭连接的写。或两者均关闭。

以上lighttpd是关闭了连接的写这一半,对于TCP套接字来说。这叫做半关闭:当前留在套接字发送缓冲区的数据仍然能够发送。可是进程不能再对其调用写函数(因为读端没有关闭,所以server仍然能够读数据),当数据发送完毕之后,TCP连接终止。

另外。注意一下:con->close_timeout_ts = srv->cur_ts;将close_timeout_ts的值设置为当前时间,在以下会用到。

在CON_STATE_CLOSE阶段:

        case CON_STATE_CLOSE:if (srv->srvconf.log_state_handling) {log_error_write(srv, __FILE__, __LINE__, "sds","state for fd", con->fd, connection_get_state(con->state));}if (con->keep_alive) {if (ioctl(con->fd, FIONREAD, &b)) {log_error_write(srv, __FILE__, __LINE__, "ss","ioctl() failed", strerror(errno));}if (b > 0) {char buf[1024];log_error_write(srv, __FILE__, __LINE__, "sdd","CLOSE-read()", con->fd, b);/* */read(con->fd, buf, sizeof(buf));} else {/* nothing to read */con->close_timeout_ts = 0;}} else {con->close_timeout_ts = 0;}if (srv->cur_ts - con->close_timeout_ts > 1) {connection_close(srv, con);if (srv->srvconf.log_state_handling) {log_error_write(srv, __FILE__, __LINE__, "sd","connection closed for fd", con->fd);}}break;

假设缓冲区中还有数据,server会把数据读出来(然后丢弃),以腾出内存空间。

假设没有数据可读,那么设置close_timeout_ts=0,关闭连接。

假设有数据可读,读取数据之后,连接依旧处在CON_STATE_CLOSE状态中(在出了CON_STATE_ERROR后。进入CON_STATE_CLOSE,这段时间cur_ts是没有改变的。假设有数据可读,此时const_time_ts是等于cur_ts的,因此连接并未被关闭),连接相应的fd被增加到fdevent系统中监听读事件。

假设缓冲区中还有数据,那么在connection_handle_fdevent 函数中,也有上面这段代码,再次执行之,直到数据读完。

随着close_timeout_ts被设置为0,在下次joblist的调度中,状态机将会关闭连接,清理全部资源。

至此,连接正式关闭。

关于状态机的简单解析就到此为止~

转载于:https://www.cnblogs.com/yutingliuyl/p/7365725.html

Lighttpd1.4.20源代码分析 笔记 状态机之错误处理和连接关闭相关推荐

  1. 热血传奇Rungate源代码分析笔记

    RunGate有三个Socket对象  一个向M2发送  一个接收客户端的连接.还有一个连接控制台(当然这个是和控制台绑定的通常手动启动是不需要的 只是在私服这方面方便私服架设      者使用) 控 ...

  2. 传世基本架构-Rungate源代码分析笔记。

    RunGate有三个Socket对象  一个向M2发送  一个接收客户端的连接.还有一个连接控制台(当然这个是和控制台绑定的通常手动启动是不需要的 只是在私服这方面方便私服架设      者使用) 控 ...

  3. VmWare工作笔记001---弹出错误提示无法连接mks:套接字连接尝试次数太多

    技术交流QQ群[JAVA,.NET,BigData,AI]:170933152 弹出错误提示无法连接mks:套接字连接尝试次数太多,这时我们点击确定按钮. 这个直接到服务中,看看有没有VMware的服 ...

  4. lighttpd1.4.18代码分析

    lighttpd1.4.18代码分析(八)--状态机(2)CON_STATE_READ状态 posted @ 2008-09-24 10:50 那谁 阅读(2225) | 评论 (1)  编辑 lig ...

  5. Linux内核源代码情景分析笔记

    Linux内核源代码情景分析笔记 好吧,首先我承认我要是读者的话,这篇文章我看着也头疼,因为写的太长太泛(其主要部分集中在内存管理,进程管理,文件系统)!原本是想按自己理解的精简精简的,按照操作系统中 ...

  6. 《深入实践Spring Boot》阅读笔记之三:核心技术源代码分析

    为什么80%的码农都做不了架构师?>>>    刚关注的朋友,可以回顾前两篇文章: 基础应用开发 分布式应用开发 上篇文章总结了<深入实践Spring Boot>的第二部 ...

  7. nux 平台的 libpcap 源代码分析

    nux 平台的 libpcap 源代码分析 施聪 (javer@163.com), 高级程序员.网络设计师 简介: libpcap 是 unix/linux 平台下的网络数据包捕获函数包,大多数网络监 ...

  8. linux内核源码分析笔记

    一.内核源码目录结构 1.Linux 内核源代码包括三个主要部分 1)内核核心代码:包括linux内核整体架构分析笔记描述的各子系统和子模块,以及其他支撑子系统,如:电源管理.linux初始化等. 2 ...

  9. Android系统默认Home应用程序(Launcher)的启动过程源代码分析

    在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还需要有一个Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home应 ...

最新文章

  1. Nature:口腔和肠道微生物可以使抗糖尿病药物(阿卡波糖)失活
  2. SSH-CLIENT : gSTM
  3. Newbe.Claptrap 框架入门,第二步 —— 创建项目
  4. C/C++端口复用SO_REUSEADDR(setsockopt参数)
  5. matlab一维插值extrap,matlab一维插值函数
  6. webstorm 2017 激活破解方法大全
  7. Python图书管理系统(终章)
  8. 跟循泰国国内游宣传曲MV,像本地人一样游曼谷
  9. UT斯达康MC8638S-高安-S905-河北联通-破解刷机线刷固件包
  10. Android中使用微信H5支付时支付结果刷新问题
  11. vue + echarts 之世界地图
  12. 网络安全产品(一)FortiSIEM
  13. 转换率是什么?如何提升转换率(CVR)?
  14. 想做好网络营销?这四步网络营销推广方法至关重要
  15. android-sdk-windows版本下载
  16. 阿伟,别打电动了,休息一下好不好
  17. H、Magic necklace
  18. 76. Lotus Notes编程中的命名习惯
  19. 3月30日—4月3日三年级课程
  20. 交换机端口镜像及其工作原理

热门文章

  1. static关键字和内存使用
  2. Java面试查漏补缺
  3. 深度优先搜索算法在RPG游戏迷宫中的应用
  4. SLAM精度测评——rpg_trajectory_evaluatio
  5. 征集佳句-精妙SQL语句收集
  6. Netbeans使用maven下载源码
  7. Linux TCP/IP协议栈笔记
  8. Redis运行流程源码解析
  9. C++拾趣——使用多态减少泛型带来的代码膨胀
  10. 【FFmpeg】降低转码延迟方法、打印信息详解、refcounted_frames详解