这里所说的错误有两种:

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_OPENSSL
if (srv_sock->is_ssl) {
/* 关闭ssl连接 */
}
ERR_clear_error();
#endif

接着:

            switch(con->mode) {
case DIRECT:
#if 0
log_error_write(srv, __FILE__, __LINE__, "sd",
"emergency exit: direct",
con->fd);
#endif
break;
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的调度中,状态机将会关闭连接,清理全部资源。

至此,连接正式关闭。

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

Lighttpd1.4.20源代码分析 笔记 状态机之错误处理和连接关闭的更多相关文章

  1. kbengine0.4.20源代码分析(一)

    基于kbengine 0.4.2 MMOPG服务端是一种高品质的工程项目,品读开源的kbe是一种乐趣.本文档我带童鞋们一起领略一下.囿于我知识面和经验方面所限,文中所述之处难免有错误存在,还请读童鞋们 ...

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

    刚关注的朋友,可以回顾前两篇文章: 基础应用开发 分布式应用开发 上篇文章总结了<深入实践Spring Boot>的第二部分,本篇文章总结第三部分,也是最后一部分.这部分主要讲解核心技术的 ...

  3. Openstack本学习笔记——Neutron-server服务加载和启动源代码分析(三)

    本文是在学习Openstack过程中整理和总结.因为时间和个人能力有限.错误之处在所难免,欢迎指正! 在Neutron-server服务载入与启动源代码分析(二)中搞定模块功能的扩展和载入.我们就回到 ...

  4. 4.View绘制分析笔记之onDraw

    上一篇文章我们了解了View的onLayout,那么今天我们来学习Android View绘制三部曲的最后一步,onDraw,绘制. ViewRootImpl#performDraw private ...

  5. 转:RTMPDump源代码分析

    0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://. ...

  6. hostapd源代码分析(一):网络接口和BSS的初始化

    [转]hostapd源代码分析(一):网络接口和BSS的初始化 原文链接:http://blog.csdn.net/qq_21949217/article/details/46004349 最近在做一 ...

  7. Hadoop源代码分析

    http://wenku.baidu.com/link?url=R-QoZXhc918qoO0BX6eXI9_uPU75whF62vFFUBIR-7c5XAYUVxDRX5Rs6QZR9hrBnUdM ...

  8. CI框架源代码阅读笔记5 基准測试 BenchMark.php

    上一篇博客(CI框架源代码阅读笔记4 引导文件CodeIgniter.php)中.我们已经看到:CI中核心流程的核心功能都是由不同的组件来完毕的.这些组件类似于一个一个单独的模块,不同的模块完毕不同的 ...

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

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

随机推荐

  1. Android ListView 和 ***Adapter 从本地/网络获取歌曲列表

    本文内容 环境 项目结构 测试数据 演示 1:SimpleAdapter 演示 2:BaseAdapter 演示 3:CustomLazyList 演示 4:CustomLazyCompleteLis ...

  2. JavaScript编程(终极篇)

    JavaScript 实现是由以下 3 个不同部分组成的:    核心(ECMAScript)    文档对象模型(DOM)    浏览器对象模型(BOM) 1.数据类型 typeof 运算符 对变量 ...

  3. 为javascript设置默认参数值

    javascript(js)中如何为函数设置默认参数值,下面提供几种方法供参考. 第一种方法: function example(a,b){ var a = arguments[0] ? argume ...

  4. Linux netstat命令介绍

    关注Linux的系统状态,主要从两个角度出发,一个角度是系统正在运行什么服务(ps命令):另外一个就是有什么连接或服务可用(netstat命令).netstat还可以显示ps无法显示的.从inetd或 ...

  5. 磁盘I/O的性能评估方法

    磁盘I/O的性能评估方法 http://blog.synology.com/blog/?p=2086 通常,我们很容易观察到数据库服务器的内存和CPU压力.但是对I/O压力没有直观的判断方法.磁盘有两 ...

  6. hadoop lzo应用

    几种压缩方式对比: LZO example: https://github.com/twitter/hadoop-lzo/blob/master/src/test/java/com/hadoop/ma ...

  7. SSH使用Slf4j

    1. Slf4j的使用 在上一篇随笔:SSH使用Log4j的基础上配置. (1)导入两个文件:slf4j-api-1.5.8.jar和slf4j-log4j12-1.5.8.jar. (2)在需要日志 ...

  8. Python有关模块学习记录

    1 pandas numpy模块 首先安装搭建好jupyter notebook,运行成功后的截图如下: 安装使用步骤(PS:确定Python安装路径和安装路径里面Scripts文件夹路径已经配置到环 ...

  9. webapck 打包体积优化策略

    一.概述 1.Tree-shaking 2.公共资源分离 3.图片压缩 二.Tree-shaking Tree-shaking:1个模块可能有多个方法,只要其中的某个方法使用到了,则整个文件都会被打到 ...

  10. java if语句

    //if语句 //Test10.java import java.util.Scanner; public class Test16{ public static void main(String[] ...