Lighttpd1.4.20源代码分析 笔记 状态机之错误处理和连接关闭
这里所说的错误有两种:
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源代码分析 笔记 状态机之错误处理和连接关闭的更多相关文章
- kbengine0.4.20源代码分析(一)
基于kbengine 0.4.2 MMOPG服务端是一种高品质的工程项目,品读开源的kbe是一种乐趣.本文档我带童鞋们一起领略一下.囿于我知识面和经验方面所限,文中所述之处难免有错误存在,还请读童鞋们 ...
- 《深入实践Spring Boot》阅读笔记之三:核心技术源代码分析
刚关注的朋友,可以回顾前两篇文章: 基础应用开发 分布式应用开发 上篇文章总结了<深入实践Spring Boot>的第二部分,本篇文章总结第三部分,也是最后一部分.这部分主要讲解核心技术的 ...
- Openstack本学习笔记——Neutron-server服务加载和启动源代码分析(三)
本文是在学习Openstack过程中整理和总结.因为时间和个人能力有限.错误之处在所难免,欢迎指正! 在Neutron-server服务载入与启动源代码分析(二)中搞定模块功能的扩展和载入.我们就回到 ...
- 4.View绘制分析笔记之onDraw
上一篇文章我们了解了View的onLayout,那么今天我们来学习Android View绘制三部曲的最后一步,onDraw,绘制. ViewRootImpl#performDraw private ...
- 转:RTMPDump源代码分析
0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://. ...
- hostapd源代码分析(一):网络接口和BSS的初始化
[转]hostapd源代码分析(一):网络接口和BSS的初始化 原文链接:http://blog.csdn.net/qq_21949217/article/details/46004349 最近在做一 ...
- Hadoop源代码分析
http://wenku.baidu.com/link?url=R-QoZXhc918qoO0BX6eXI9_uPU75whF62vFFUBIR-7c5XAYUVxDRX5Rs6QZR9hrBnUdM ...
- CI框架源代码阅读笔记5 基准測试 BenchMark.php
上一篇博客(CI框架源代码阅读笔记4 引导文件CodeIgniter.php)中.我们已经看到:CI中核心流程的核心功能都是由不同的组件来完毕的.这些组件类似于一个一个单独的模块,不同的模块完毕不同的 ...
- Android系统默认Home应用程序(Launcher)的启动过程源代码分析
在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还需要有一个 Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home ...
随机推荐
- springboot项目中报错:listener does not currently know of SID given in connect descriptor
springboot项目中报错:listener does not currently know of SID given in connect descriptor 出现这个问题的原因是SID写错了 ...
- Swift语言精要-闭包(Closure)
闭包(Closure)这个概念如果没学过Swift的人应该也不会陌生. 学过Javascript的朋友应该知道,在Javascript中我们经常会讨论闭包,很多前端工程师的面试题也会问到什么是闭包. ...
- 查看JAVA的class二进制文件的方法
hexdump -C filename可以查看二进制文件. 比如java的Test.java public class Test{ public static void main(String[] a ...
- Javascript中怎样获取统一管理的Java提示语
项目开发中,各个页面.各个业务操作都会使用提示语.面对这么多message,更好的方式是统一管理这些消息. 这样在做国际化的时候进行统一处理也变的方便. 推荐方案使用数据库来管理全部提示语,在项目启动 ...
- A Dog's Way Home插曲列表
The movie songs A Dog's Way Home 文章来源:刘俊涛的博客 欢迎关注,有问题一起学习欢迎留言.评论
- MongoDB内存管理机制
目前,MongoDB使用的是内存映射存储引擎,它会把磁盘IO操作转换成内存操作,如果是读操作,内存中的数据起到缓存的作用,如果是写操作,内存还可以把随机的写操作转换成顺序的写操作,总之可以大幅度提升性 ...
- Hibernate学习笔记四:事务管理
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6768298.html 一:需要事务的Session操作 Session操作中,查询类操作是不需要事务就能生效 ...
- Java多线程之锁优化策略
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6561264.html 锁的优化策略 编码过程中可采取的锁优化的思路有以下几种: 1:减少锁持有时间 例如:对 ...
- 〖Android〗Android源代码所有目录生成的Target(编译生成文件反查)
=> build/tools/zipalign: out/host/linux-x86/bin/zipalign (host) => build/tools/atree: out/host ...
- 1253 Dungeon Master
题目链接: http://noi.openjudge.cn/ch0205/1253/ http://poj.org/problem?id=2251 总时间限制: 1000ms 内存限制: 65536 ...