这里所说的错误有两种:

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 原生 Android ActionBar Tab (滑动)导航

    本文内容 环境 项目结构 演示一:ActionBar Tab 导航 演示二:ActionBar Tab 带滑动导航 本文演示 Tab 导航.第一个演示,是基本的 Tab 导航,第二个是带滑动的 Tab ...

  2. spring 判断非空提示断言

    org.springframework.util.Assert Assert.notNull(object, "Bean object must not be null");

  3. ZH奶酪:PHP 使用DOMDocument操作XML

    原文链接:http://my.oschina.net/zhangb081511/blog/160113 PHP写XML方法很多,这里主要介绍一下DOMDocument的用法,跟 JS大体上相同,其实非 ...

  4. Android 在闹钟开机时,如何解决开机动画没有播完就进入Launcher M

    前言          欢迎大家我分享和推荐好用的代码段~~ 声明          欢迎转载,但请保留文章原始出处:          CSDN:http://www.csdn.net        ...

  5. tomcat7配置

    <?xml version='1.0' encoding='utf-8'?><!-- Licensed to the Apache Software Foundation (ASF) ...

  6. 如何设置Vmware下Linux系统全屏显示

    环境:Vmware10+RedHat5 在Vmware10中安装好RedHat5后,即使点击了全屏按钮(或使用快捷键Ctrl+Alt+Enter),全屏的效果依然不尽人意,跟下图中差不多,RedHat ...

  7. 压力测试 JMeter3.3

    历史下载版本 https://archive.apache.org/dist/jmeter/source/

  8. 利用mvn进行多环境配置

    代码里的resource信息有很多,代码里写死某一个环境的配置的话,有以下若干问题. 1. dev,不同的beta上,使用的resource信息不同. 2. 代码没有发布到对应的环境上,需要去机器上需 ...

  9. pip安装psutil模块时候报错:yum install python-devel mysql-devel zlib-devel openssl-devel

    yum install python-devel mysql-devel zlib-devel openssl-devel [root@localhost software]# pip install ...

  10. percona-Toolkit

    1:下载最新安装包 wget https://www.percona.com/downloads/percona-toolkit/2.1.1/percona-toolkit-2.1.1.tar.gz ...